﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////
#Область СлужебныйПрограммныйИнтерфейс

// Возвращает информацию о доступности адресных сведений.
// 
// Возвращаемое значение:
//  ФиксированноеСоответствие из КлючИЗначение:
//   * Ключ - Строка - "КлассификаторДоступен", "ИспользоватьЗагруженные"
//   * Значение - Булево
//
Функция СведенияОДоступностиАдресныхСведений() Экспорт
	Возврат АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
КонецФункции

// Проверка доступности поставщика - локальной базы или сервиса.
// 
// Возвращаемое значение:
//     Структура:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Данные                       - Строка - описание версии поставщика.
//
Функция ВерсияПоставщикаДанных() Экспорт

	Результат = Новый Структура("Данные");
	СтруктураОписанияОшибкиПоставщика(Результат);
	
	// В модели сервиса веб-сервис доступен всегда.
	Если Не ЗаполненыДанныеАутентификацииПользователяИнтернетПоддержки() Тогда
		Возврат Результат; // ИПП не подключена.
	КонецЕсли;

	Попытка
		ЗаполнитьВерсиюПоставщикаДанныхСервис1С(Результат);
	Исключение
		// Веб сервис 1С, может быть на обслуживании.
		СтруктураОписанияОшибкиПоставщика(Результат, ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
			Результат.ПодробноеПредставлениеОшибки);
	КонецПопытки;

	Возврат Результат;

КонецФункции

// Возвращает описание последней загрузки классификатора.
//
// Возвращаемое значение:
//     Структура:
//         * ДатаПоследнейЗагрузки              - Дата   - дата последней загрузки (часовой пояс сеанса).
//         * УниверсальнаяДатаПоследнейЗагрузки - Дата   - дата последней загрузки (UTC).
//         * ДнейНазад                          - Число  - количество дней от последней загрузки.
//         * Представление                      - Строка - описание, например "Адресный классификатор был загружен
//                                                         сегодня.";
//         * НеобходимоОбновление               - Булево - Истина, если количество дней от последней загрузки превышает
//                                                         период актуальности.
//
Функция ОписаниеПоследнейЗагрузки(ИдентификаторРегиона = Неопределено) Экспорт

	Результат = Новый Структура("ДнейНазад, ДатаПоследнейЗагрузки, УниверсальнаяДатаПоследнейЗагрузки, Представление, НеобходимоОбновление");
	Запрос = Новый Запрос;
	
	// Определяем дату последней загрузки.
	Если ЗначениеЗаполнено(ИдентификаторРегиона) Тогда
		ТекстЗапроса = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ЕСТЬNULL(ЗагруженныеВерсииАдресныхСведений.ДатаВерсии, ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)) КАК ДатаЗагрузки
		|ИЗ
		|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ПРАВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗагруженныеВерсииАдресныхСведений КАК ЗагруженныеВерсииАдресныхСведений
		|		ПО АдресныеОбъекты.КодСубъектаРФ = ЗагруженныеВерсииАдресныхСведений.КодСубъектаРФ
		|	ГДЕ АдресныеОбъекты.Идентификатор = &ИдентификаторРегиона
		|
		|УПОРЯДОЧИТЬ ПО
		|	ДатаВерсии";

		Запрос.УстановитьПараметр("ИдентификаторРегиона", Новый УникальныйИдентификатор(ИдентификаторРегиона));
	Иначе
		ТекстЗапроса = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ЕСТЬNULL(ЗагруженныеВерсииАдресныхСведений.ДатаВерсии, ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)) КАК ДатаЗагрузки
		|ИЗ
		|	РегистрСведений.ЗагруженныеВерсииАдресныхСведений КАК ЗагруженныеВерсииАдресныхСведений
		|УПОРЯДОЧИТЬ ПО
		|	ДатаЗагрузки УБЫВ";
	КонецЕсли;
	Запрос.Текст = ТекстЗапроса;
	Выборка = Запрос.Выполнить().Выбрать();

	Если Выборка.Следующий() Тогда
		ДатаПоследнейЗагрузки = Выборка.ДатаЗагрузки;
	Иначе
		Результат.НеобходимоОбновление = Ложь;
		Результат.Представление        = НСтр("ru = 'Адресный классификатор еще не загружался.'");
		Возврат Результат;
	КонецЕсли;

	Результат.УниверсальнаяДатаПоследнейЗагрузки = ДатаПоследнейЗагрузки;
	Результат.ДатаПоследнейЗагрузки              = МестноеВремя(ДатаПоследнейЗагрузки, ЧасовойПоясСеанса());

	НачалоПериода = НачалоДня(ТекущаяУниверсальнаяДата());
	КонецПериода  = НачалоДня(ДатаПоследнейЗагрузки);
	ДнейРазницы   = Цел((НачалоПериода - КонецПериода) / 86400);
	Представление = "";

	Если ДнейРазницы = 0 Тогда
		Представление = НСтр("ru = 'Адресный классификатор был загружен сегодня.'");

	ИначеЕсли ДнейРазницы = 1 Тогда
		Представление = НСтр("ru = 'Адресный классификатор был загружен вчера.'");

	ИначеЕсли ДнейРазницы = 2 Тогда
		Представление = НСтр("ru = 'Адресный классификатор был загружен позавчера.'");

	ИначеЕсли ДнейРазницы > 2 Тогда
		Представление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
			"ru = 'Адресный классификатор был загружен %1 назад.'"), ОбщегоНазначения.ИнтервалВремениСтрокой(
			КонецПериода, НачалоПериода));
	КонецЕсли;

	Результат.НеобходимоОбновление = ДнейРазницы > 30; // 1 месяц
	Результат.ДнейНазад            = ДнейРазницы;
	Результат.Представление        = Представление;

	Возврат Результат;
КонецФункции

// Возвращает данные классификатора по почтовому индексу.
//
// Параметры:
//     Индекс                  - Число     - почтовый индекс, для которого необходимо получать данные.
//     ДополнительныеПараметры - Структура - описание настроек поиска. Поля:
//         * ФорматАдреса - Строка - тип используемого классификатора.
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * ОбщаяЧастьПредставления      - Строка - общая часть представлений адреса.
//       * Данные                       - ТаблицаЗначений - содержит данные для выбора. Колонки:
//             ** Неактуален    - Булево - флаг неактуальности строки данных.
//             ** Идентификатор - УникальныйИдентификатор - код классификатора для поиска вариантов по индексу.
//             ** Представление - Строка - представление варианта.
//
Функция АдресаПоПочтовомуИндексуКлассификатора(Индекс, ДополнительныеПараметры) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("Данные", ТаблицаДанныхДляВыбораПоПочтовомуИндексу());
	Результат.Вставить("ОбщаяЧастьПредставления", "");
	
	СтруктураОписанияОшибкиПоставщика(Результат);

	ЗаполнитьАдресаПоПочтовомуИндексуИзЗагруженныхДанных(Результат, Индекс, ДополнительныеПараметры);

	Если Результат.Данные.Количество() = 0 И Не Результат.Отказ Тогда

		Попытка
			ЗаполнитьАдресаПоПочтовомуИндексуКлассификатораСервис1С(Результат, Индекс);
		Исключение
			СтруктураОписанияОшибкиПоставщика(Результат, ИнформацияОбОшибке());
			ЗаписьЖурналаРегистрации( СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
				Результат.ПодробноеПредставлениеОшибки);
		КонецПопытки;

	КонецЕсли;

	Возврат Результат;
КонецФункции

// Определить регион по индексу.
//
// Параметры:
//  Индекс - Строка - почтовый индекс определимого региона.
// 
// Возвращаемое значение:
//  Структура - код и наименование региона, Неопределенно - если регион не найден:
//    * КодСубъектаРФ - Число - код субъекта РФ.
//    * Представление - Строка - представление субъекта РФ.
//
Функция ОпределитьРегионПоИндексу(Индекс) Экспорт
	Сведения = СведенияОСубъектахРФ();
	Результат = Новый Структура("Представление, КодСубъектаРФ");

	ПервыйТриЦифрыИндекса = Число(Лев(Индекс, 3));
	Для Каждого Регион Из Сведения Цикл
		ДиапазонПочтовыхИндексов = Регион.ДиапазонПочтовыхИндексов;
		Диапазоны = СтрРазделить(ДиапазонПочтовыхИндексов, ",");
		Для Каждого Диапазон Из Диапазоны Цикл
			Интервалы = СтрРазделить(Диапазон, "-");
			Если Интервалы.Количество() = 1 Тогда
				Если Число(Интервалы[0]) = ПервыйТриЦифрыИндекса Тогда
					Результат.КодСубъектаРФ = Регион.КодСубъектаРФ;
					Результат.Представление = ПредставлениеРегиона(Регион.Наименование, Регион.Сокращение);
					Возврат Результат;
				КонецЕсли;
			Иначе
				Если Число(Число(Интервалы[1])) >= ПервыйТриЦифрыИндекса И Число(Интервалы[0]) <= ПервыйТриЦифрыИндекса Тогда
					Результат.КодСубъектаРФ = Регион.КодСубъектаРФ;
					Результат.Представление = ПредставлениеРегиона(Регион.Наименование, Регион.Сокращение);
					Возврат Результат;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;

	Возврат Неопределено;
КонецФункции

Функция ПолноеНаименованиеРегионаПоКоду(КодРегиона) Экспорт

	НаименованияРегионов = АдресныйКлассификаторПовтИсп.ПолныеНаименованияРегионов();
	НаименованиеРегиона = НаименованияРегионов.Получить(КодРегиона);

	Если НаименованиеРегиона = Неопределено Тогда
		Возврат "";
	КонецЕсли;

	Возврат НаименованиеРегиона;

КонецФункции

// Локальная проверка одного адреса.
//
Процедура УстановитьИдентификаторыАдреса(Адрес, Источник = "") Экспорт

	Адреса = Новый Соответствие;
	Адреса.Вставить(1, Адрес);
	УстановитьИдентификаторыАдресов(Адреса, Источник);

КонецПроцедуры

Процедура УстановитьИдентификаторыАдресов(Адреса, Источник = "") Экспорт

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	АдресаВебСервис = Новый Соответствие;
	АдресаЗагруженныеДанные = Новый Соответствие;

	Для Каждого КлючЗначение Из Адреса Цикл
		Адрес = КлючЗначение.Значение;
		КодРегиона = АдресныйКлассификатор.КодРегионаПоНаименованию(СоединитьНаименованиеИТипАдресногоОбъекта(
			Адрес.Area, Адрес.AreaType, Истина));

		Если ТипЗнч(КодРегиона) = Тип("Число") Тогда
			Если Источник <> "Сервис1С" И ЗагруженныеАдресныеСведения.Получить(КодРегиона) <> Неопределено
				И ЗагруженныеАдресныеСведения.Получить(КодРегиона).ИспользоватьЗагруженные Тогда
				АдресаЗагруженныеДанные.Вставить(КлючЗначение.Ключ, Адрес);

			ИначеЕсли ЗагруженныеАдресныеСведения.Получить("КлассификаторДоступен") = Истина Или Источник = "Сервис1С" Тогда
				АдресаВебСервис.Вставить(КлючЗначение.Ключ, Адрес);
			КонецЕсли;

		КонецЕсли;

	КонецЦикла;

	Если АдресаЗагруженныеДанные.Количество() > 0 Тогда
		УстановитьИдентификаторыАдресовПоЗагруженнымДанным(АдресаЗагруженныеДанные);
	КонецЕсли;

	Если АдресаВебСервис.Количество() > 0 Тогда
		УстановитьИдентификаторыАдресаЧерезВебСервис(АдресаВебСервис);
	КонецЕсли;

КонецПроцедуры

Процедура УстановитьМуниципальныеСведения(Адрес, ОКТМО, ИдентификаторАдреса = Неопределено, ЗагруженныеДанные = Истина) Экспорт

	Если ЗначениеЗаполнено(ИдентификаторАдреса) Тогда

		СведенияОбАдресномОбъекта = СведенияОбАдресномОбъекта(ИдентификаторАдреса);
		СведенияОбАдресномОбъекта.Адрес             = Адрес;
		СведенияОбАдресномОбъекта.Муниципальный     = ЭтоМуниципальныйАдрес(Адрес.addressType);
		СведенияОбАдресномОбъекта.ЗагруженныеДанные = ЗагруженныеДанные;
		
		Результат = АктуальныеАдресныеСведения(СведенияОбАдресномОбъекта);
		
		Если Не Результат.Отказ Тогда
		
			ЗаполнитьЗначенияСвойств(Адрес, Результат.Данные,
				"munDistrict, munDistrictType,munDistrictId,settlement,settlementType,settlementId");
		
		КонецЕсли;

	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ЕСТЬNULL(АдресныеОбъекты.Идентификатор, """") КАК Идентификатор,
	|	ЕСТЬNULL(АдресныеОбъекты.Наименование,  """") КАК Наименование,
	|	ЕСТЬNULL(АдресныеОбъекты.ТипОбъекта,    """") КАК ТипОбъекта,
	|	ЕСТЬNULL(АдресныеОбъекты.Уровень, 0) КАК Уровень
	|ИЗ
	|	РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО ДополнительныеСведения.Идентификатор = АдресныеОбъекты.ДополнительныеАдресныеСведения
	|ГДЕ
	|	ДополнительныеСведения.ОКТМО = &ОКТМО
	|	И (АдресныеОбъекты.Уровень = &УровеньРайона
	|		ИЛИ АдресныеОбъекты.Уровень = &УровеньПоселения)";

	Запрос.УстановитьПараметр("ОКТМО", ОКТМО);
	Запрос.УстановитьПараметр("УровеньРайона",    АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().munDistrict);
	Запрос.УстановитьПараметр("УровеньПоселения", АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().settlement);

	РезультатЗапроса = Запрос.Выполнить();

	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;

	СловарьИменПолей = СловарьКлючейПолейАдресВСоответствииСУровнем();

	Для Каждого ЗаписьУровня Из РезультатЗапроса.Выгрузить() Цикл

		ИмяУровня = СловарьИменПолей[ЗаписьУровня.Уровень];
		Адрес[ИмяУровня]          = ЗаписьУровня.Наименование;
		Адрес[ИмяУровня + "Type"] = ЗаписьУровня.ТипОбъекта;
		Адрес[ИмяУровня + "Id"]   = ЗаписьУровня.Идентификатор;

	КонецЦикла;

КонецПроцедуры

Функция РаспознатьАдрес(ЧастиАдреса, Представление, ВСтруктуру = Ложь) Экспорт

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	КодРегиона = ОпределитьКодРегионаПоЧастямАдреса(ЧастиАдреса);

	Если ЗагруженныеАдресныеСведения.Получить("ИспользоватьЗагруженные") = Истина 
	   И ТипЗнч(ЗагруженныеАдресныеСведения.Получить(КодРегиона)) = Тип("Структура") 
	   И ЗагруженныеАдресныеСведения.Получить(КодРегиона).ИспользоватьЗагруженные Тогда
		
		Адрес = РаспознатьАдресЗагруженныеДанные(ЧастиАдреса, КодРегиона);
		Если СтрСравнить(Адрес.addressType, АдресВСвободнойФорме()) <> 0 Тогда
			Возврат Адрес;
		КонецЕсли;
		
	ИначеЕсли ЗагруженныеАдресныеСведения.Получить("КлассификаторДоступен") = Истина Тогда
		
		Адрес = РаспознатьАдресВебСервис(ЧастиАдреса, Представление, ВСтруктуру);
		Возврат Адрес;
		
	КонецЕсли;

	Возврат Неопределено;

КонецФункции

// Проверка адрес на соответствие адресному классификатору
//
// Параметры:
//  Адреса - Соответствие из КлючИЗначение:
//   * Ключ - Число - уникальный ключ адреса,
//   * Значение - Строка - строка в формате JSON с адресом.
//  ПроверятьУстареваниеАдресов - Булево
// 
// Возвращаемое значение:
//   см. РезультатПроверкиАдресов
//
Функция АнализАдресовПоКлассификатору(Знач Адреса, ПроверятьУстареваниеАдресов = Ложь) Экспорт

	АдресаJSON = Новый Соответствие;
	Для Каждого Адрес Из Адреса Цикл
		АдресаJSON.Вставить(Адрес.Ключ, JSONВКонтактнуюИнформациюПоПолям(Адрес.Значение));
	КонецЦикла;

	Возврат РезультатПроверкиАдресов(АдресаJSON, ПроверятьУстареваниеАдресов);

КонецФункции

// Возвращает данные классификатора поля выбора по уровню.
//
// Параметры:
//   Родитель   - УникальныйИдентификатор - родительский объект.
//   Уровень   - Число - уровень данных для выбора
//   ТипАдреса - Строка - варианты: Муниципальный, Административно-территориальный
//   ДополнительныеПараметры - Структура               - описание настроек поиска:
//     * ФорматАдреса - Строка  - тип используемого классификатора.
//     * РазмерПорции - Число                   - необязательный размер порции возвращаемых данных. Если не указано
//                                                или 0, то возвращает все элементы.
//     * ПерваяЗапись - УникальныйИдентификатор - элемент, с которого начинается порция данных. Сам элемент не
//                                                входит в выборку.
//     * Сортировка   - Строка                  - направление сортировки для порции.
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Заголовок                    - Строка - строка с предложением выбора.
//       * Данные                       - ТаблицаЗначений - содержит данные для выбора. Колонки:
//             ** Неактуален     - Булево - флаг неактуальности строки данных.
//             ** Идентификатор  - УникальныйИдентификатор - код классификатора для поиска вариантов по индексу.
//             ** Представление  - Строка - представление варианта.
//             ** РегионЗагружен - Булево - имеет смысл только для регионов. Истина, если есть записи.
//
Функция АдресаДляИнтерактивногоВыбора(Родитель, Уровень, ТипАдреса, ДополнительныеПараметры) Экспорт

	Результат = Новый Структура("Данные, Заголовок", ТаблицаДанныхДляИнтерактивногоВыбора());
	СтруктураОписанияОшибкиПоставщика(Результат);

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] 
		Или Уровень = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().area Тогда
			ЗаполнитьАдресаДляВыбораПоЗагруженнымДанным(Результат, Родитель, Уровень, ТипАдреса, ДополнительныеПараметры);
	КонецЕсли;

	Если Результат.Данные.Количество() = 0 И ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина Тогда
	
		// Веб сервис 1С, может быть на обслуживании.
		Попытка

			Если ДополнительныеПараметры.Свойство("КоличествоЗаписей") Тогда
				КоличествоЗаписей = Формат(ДополнительныеПараметры.КоличествоЗаписей, "ЧГ=0");
			Иначе
				КоличествоЗаписей = "20";
			КонецЕсли;

			ПараметрыПоиска = Новый Массив;
			ПараметрыПоиска.Добавить("select?level=%1&addressType=%2&limit=%3");
			
			Если Уровень > 1 Тогда
				ПараметрыПоиска.Добавить("parentId=" + Строка(Родитель));
			КонецЕсли;
			
			Если ДополнительныеПараметры.Свойство("Позиция") Тогда
				Позиция = Формат(ДополнительныеПараметры.Позиция, "ЧГ=0");
				ПараметрыПоиска.Добавить("from=" + Позиция);
			КонецЕсли;
			
			Если ДополнительныеПараметры.Свойство("СтрокаПоиска") И ЗначениеЗаполнено(
				ДополнительныеПараметры.СтрокаПоиска) Тогда
				ПараметрыПоиска.Добавить("text=" + ДополнительныеПараметры.СтрокаПоиска);
			КонецЕсли;
			
			ШаблонЗапроса = СтрСоединить(ПараметрыПоиска, "&");
			
			ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗапроса, Строка(Уровень),
				ТипАдресаДляВебСервиса(ТипАдреса), КоличествоЗаписей);
			
			РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

			Если РезультатВебСервис.Отказ Тогда
				Возврат Результат;
			КонецЕсли;

			ИмяПоля = ?(ЭтоМуниципальныйАдрес(ТипАдреса), "munName", "name");
			ИмяИдентификатора = ?(ЭтоМуниципальныйАдрес(ТипАдреса), "munId", "id");
			Для Каждого СтрокаРезультатаВебСервис Из РезультатВебСервис.Данные Цикл
				НоваяСтрока = Результат.Данные.Добавить();
				Если ЗначениеЗаполнено(СтрокаРезультатаВебСервис[ИмяПоля]) Тогда
					НоваяСтрока.Идентификатор  = СтрокаРезультатаВебСервис[ИмяИдентификатора];
					НоваяСтрока.Представление  = СтрокаРезультатаВебСервис[ИмяПоля];
				Иначе
					ИмяПоля1 = ?(ИмяПоля = "munName", "name", "munName");
					ИмяИдентификатора1 =  ?(ИмяПоля = "munName", "id", "munId");
					НоваяСтрока.Идентификатор  = СтрокаРезультатаВебСервис[ИмяИдентификатора1];
					НоваяСтрока.Представление  = СтрокаРезультатаВебСервис[ИмяПоля1];
				КонецЕсли;
				НоваяСтрока.РегионЗагружен = Ложь;
				НоваяСтрока.Неактуален     = Ложь;
			КонецЦикла;

		Исключение
			СтруктураОписанияОшибкиПоставщика(Результат, ИнформацияОбОшибке());
			ЗаписьЖурналаРегистрации( СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
				Результат.ПодробноеПредставлениеОшибки);
		КонецПопытки;

	КонецЕсли;

	Если Уровень = 1 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите регион'");
	ИначеЕсли Уровень = 2 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите район'");
	ИначеЕсли Уровень = 3 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите муниципальный район'");
	ИначеЕсли Уровень = 4 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите поселение'");
	ИначеЕсли Уровень = 5 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите город'");
	ИначеЕсли Уровень = 6 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите населенный пункт'");
	ИначеЕсли Уровень = 7 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите территорию'");
	ИначеЕсли Уровень = 8 Тогда
		Результат.Заголовок = НСтр("ru = 'Выберите улицу'");
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Возвращает данные классификатора поля выбора по уровню.
//
// Параметры:
//     Родитель  - УникальныйИдентификатор - родительский адресный объект.
//     Уровень   - Число -  уровень данных для выбора.
//     ТипАдреса - Строка -Варианты: Муниципальный, Административно-территориальный.
//     СтрокаПоиска - Строка - если указана, то будут отобраны адресные сведения совпадающей со строкой.  
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Заголовок                    - Строка - строка с предложением выбора.
//       * Данные                       - ТаблицаЗначений - содержит данные для выбора. Колонки:
//             ** Неактуален     - Булево - флаг неактуальности строки данных.
//             ** Идентификатор  - УникальныйИдентификатор - код классификатора для поиска вариантов по индексу.
//             ** Представление  - Строка - представление варианта.
//             ** РегионЗагружен - Булево - имеет смысл только для регионов. Истина, если есть записи.
//
Функция АдресныеОбъектыУровня(Родитель, Уровень, ТипАдреса, Знач СтрокаПоиска = "") Экспорт

	ДанныеАдресныхОбъектов = Новый Структура("Данные, Отказ", Новый СписокЗначений, Ложь);
	ДанныеАдресныхОбъектов.Вставить("ПодробноеПредставлениеОшибки", "");
	ДанныеАдресныхОбъектов.Вставить("КраткоеПредставлениеОшибки", "");

	Результат = Новый Структура("Данные", ТаблицаДанныхДляИнтерактивногоВыбора());
	СтруктураОписанияОшибкиПоставщика(Результат);

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	ПредлагатьЗагрузкуСведений = (Уровень = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().area
		И ЗагруженныеАдресныеСведения.Получить("КлассификаторДоступен") = Ложь);

	Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
		ПреобразоватьВводАдреса(СтрокаПоиска);
	КонецЕсли;

	Если ЗагруженныеАдресныеСведения.Получить("ИспользоватьЗагруженные") Или Уровень = 1 Тогда
		ДополнительныеПараметры = Новый Структура("СтрокаПоиска", СтрокаПоиска);
		ЗаполнитьАдресаДляВыбораПоЗагруженнымДанным(Результат, Родитель, Уровень, ТипАдреса, ДополнительныеПараметры);

		Для Каждого СведенияОбАдресе Из Результат.Данные Цикл
			
			АдресныйОбъект = СведенияОбПодбираемомАдресномОбъекте();
			
			ЗаполнитьЗначенияСвойств(АдресныйОбъект, СведенияОбАдресе);
			АдресныйОбъект.Родитель          = Родитель;
			АдресныйОбъект.ЗагруженныеДанные = Истина;

			Если ПредлагатьЗагрузкуСведений Тогда
				АдресныйОбъект.ПредлагатьЗагрузкуКлассификатора = Не СведенияОбАдресе.РегионЗагружен;
			КонецЕсли;

			Представление = СтрНайтиИВыделитьОформлением(СведенияОбАдресе.Представление, СтрокаПоиска);

			Если Представление = Неопределено Тогда
				Представление = СведенияОбАдресе.Представление;
			КонецЕсли;

			ДанныеАдресныхОбъектов.Данные.Добавить(АдресныйОбъект, Представление);
		КонецЦикла;

	КонецЕсли;

	Если Результат.Данные.Количество() = 0 И ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина Тогда
	
		// Веб сервис 1С, может быть на обслуживании.
		Попытка

			СтрокаЗапроса = "select?level=%1&addressType=%2&limit=20";

			Если ЗначениеЗаполнено(Родитель) Тогда
				СтрокаЗапроса = СтрокаЗапроса + "&parentId=" + СокрЛП(Родитель);
			КонецЕсли;

			Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
				СтрокаЗапроса = СтрокаЗапроса + "&text=" + СокрЛП(СтрокаПоиска);
			КонецЕсли;

			ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаЗапроса, XMLСтрока(Уровень),
				ТипАдресаДляВебСервиса(ТипАдреса));
			РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

			ИмяПоля              = ?(ЭтоМуниципальныйАдрес(ТипАдреса), "munName", "name");
			ИмяПоляИдентификатор = ?(ЭтоМуниципальныйАдрес(ТипАдреса), "munId", "id");
			ИмяУровня = ИменаУровнейАдресаПоКоду().Получить(Уровень);
			
			ДобавленныеПредставленияАдресногоОбъекта = Новый Соответствие();
			
			Для Каждого СтрокаДанных Из РезультатВебСервис.Данные Цикл
				
				Если ЗначениеЗаполнено(СтрокаДанных[ИмяПоляИдентификатор]) Тогда
					Если ДанныеАдресныхОбъектов.Данные.НайтиПоЗначению(СтрокаДанных[ИмяПоляИдентификатор])
						= Неопределено Тогда
						Представление = СтрокаДанных[ИмяПоля];
						Идентификатор = СтрокаДанных[ИмяПоляИдентификатор];
					КонецЕсли;
				Иначе
					ИмяПоляАльтернативное = ?(ИмяПоля = "munName", "name", "munName");
					ИмяПоляИдентификаторАльтернативное = ?(ИмяПоля = "munName", "id", "munId");
					Если ЗначениеЗаполнено(СтрокаДанных[ИмяПоляИдентификаторАльтернативное]) Тогда
						Представление = СтрокаДанных[ИмяПоляАльтернативное];
						Идентификатор = СтрокаДанных[ИмяПоляИдентификаторАльтернативное];
					КонецЕсли;
				КонецЕсли;
				
				Если ПустаяСтрока(Представление)
					Или ДобавленныеПредставленияАдресногоОбъекта.Получить(Представление) = Истина Тогда
						Продолжить;
				КонецЕсли;
				
				АдресныйОбъект = СведенияОбПодбираемомАдресномОбъекте();
				АдресныйОбъект.Представление = Представление;
				АдресныйОбъект.Идентификатор = Идентификатор;
				АдресныйОбъект.Наименование  = СтрокаДанных[ИмяУровня];
				АдресныйОбъект.ТипОбъекта    = СтрокаДанных[ИмяУровня + "Type"];
				АдресныйОбъект.Родитель      = Родитель;
				АдресныйОбъект.Уровень       = Уровень;
				
				ДобавленныеПредставленияАдресногоОбъекта.Вставить(АдресныйОбъект.Представление, Истина);
				
				Представление = СтрНайтиИВыделитьОформлением(АдресныйОбъект.Представление, СтрокаПоиска);

				Если Представление = Неопределено Тогда
					Представление = АдресныйОбъект.Представление;
				КонецЕсли;
			
				ДанныеАдресныхОбъектов.Данные.Добавить(АдресныйОбъект, Представление);
			КонецЦикла;

			Если РезультатВебСервис.Отказ Тогда
				ДанныеАдресныхОбъектов.Отказ = Истина;
				Возврат ДанныеАдресныхОбъектов;
			КонецЕсли;

		Исключение
			СтруктураОписанияОшибкиПоставщика(Результат, ИнформацияОбОшибке());
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
				Результат.ПодробноеПредставлениеОшибки);
			ДанныеАдресныхОбъектов.ПодробноеПредставлениеОшибки = Результат.ПодробноеПредставлениеОшибки;
			ДанныеАдресныхОбъектов.КраткоеПредставлениеОшибки   = Результат.КраткоеПредставлениеОшибки;
		КонецПопытки;

	КонецЕсли;

	Возврат ДанныеАдресныхОбъектов;
КонецФункции

// Возвращает список для автоподбора элемента адреса, поиск по подобию.
//
// Параметры:
//     Текст                   - Строка                      - текст, введенный в поле.
//     Родитель                - УникальныйИдентификатор     - родительский объект.
//     Уровни                  - Массив
//                             - ФиксированныйМассив - набор требуемых уровней данных. 1-7, 90, 91 - адресные
//                               объекты, -1 - ориентиры.
//     ДополнительныеПараметры - Структура                   - описание настройке поиска. Поля:
//         * ТолькоВебСервис - Булево - автоподбор только через веб-сервис.
//         * ТипАдреса       - Строка - тип используемого классификатора.
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Данные                       - СписокЗначений - содержит данные для выбора. Колонки:
//             ** Представление  - Строка - представление варианта.
//             ** Значение       - Структура - с полями Идентификатор, Муниципальный, ЗагруженныеДанные.
//
Функция ВариантыАвтоподбора(Текст, ДополнительныеПараметры) Экспорт

	Результат        = Новый СписокЗначений;
	СписокПредставлений = Новый Соответствие;

	ТолькоВебСервис = ДополнительныеПараметры.ТолькоВебСервис;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	Если Не ТолькоВебСервис Тогда
		
		ЗаполнитьСписокАвтоподбораПоЗагруженнымДанным(Результат,
			СписокПредставлений, Текст, ДополнительныеПараметры, ЗагруженныеАдресныеСведения);
		
		Если Результат.Количество() >= 20 Тогда
			Возврат Результат;
		КонецЕсли;
		
	КонецЕсли;
	
	// Веб сервис 1С
	Если ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина Тогда

		Родитель = Неопределено;
		Если ДополнительныеПараметры.Свойство("Уровень") Тогда
			Если ДополнительныеПараметры.Уровень > 1 Тогда
				Родитель = ДополнительныеПараметры.Идентификатор;
			КонецЕсли;
		КонецЕсли;
		
		// Адаптация текста под поиск
		ЧастиАдреса = СтрРазделить(Текст, ",");
		Если ЧастиАдреса.Количество() > 0 Тогда
			Если СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(СокрЛП(ЧастиАдреса[0])) Тогда
				ЧастиАдреса.Удалить(0);
			КонецЕсли;
			
			ТекстПоиска = СокрЛП(СтрСоединить(ЧастиАдреса, ","));
			
			ЗаполнитьСписокАвтоподбораЧастиАдресаСервис1С(Результат,
				СписокПредставлений, ТекстПоиска, Родитель, 20, ДополнительныеПараметры);
			
		КонецЕсли;
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Возвращает список домов по идентификатору адресного объекта, поиск по подобию.
//
// Параметры:
//     ИдентификаторАдресногоОбъекта                - УникальныйИдентификатор     - родительский объект.
//     СтрокаПоиска                  - Строка                      - текст, отбора в списке домов.
//     ПорцияПриПоиске - Число - кол-во получаемых вариантов за один запрос.
//
// Возвращаемое значение:
//   см. КонструкторСпискаДомов
//
Функция СписокДомов(ИдентификаторАдресногоОбъекта, Знач СтрокаПоиска, ПорцияПриПоиске = 20) Экспорт

	ВариантыДомов = КонструкторСпискаДомов();

	Если СтрЗаканчиваетсяНа(СтрокаПоиска, "%") Тогда
		ТочноеСовпадение = Ложь;
		СтрокаПоиска     = Лев(СтрокаПоиска, СтрДлина(СтрокаПоиска) - 1);
	Иначе
		ТочноеСовпадение = Истина;
	КонецЕсли;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] Тогда

		СписокДомовИзЗагруженныхСведений(ВариантыДомов, ИдентификаторАдресногоОбъекта, СтрокаПоиска, ТочноеСовпадение);

	КонецЕсли;

	Если ВариантыДомов.Количество() = 0 И ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина Тогда

		ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("selectHouse?parentId=%1&limit=%2",
			Строка(ИдентификаторАдресногоОбъекта), Формат(ПорцияПриПоиске, "ЧГ=0"));
		Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
			ТекстGETЗапроса = ТекстGETЗапроса + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("&text=%1",
				СокрЛП(СтрокаПоиска));
		КонецЕсли;

		РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

		Если РезультатВебСервис.Отказ Тогда
			Возврат ВариантыДомов;
		КонецЕсли;

		НаименованиеЗданийИСтроений = АдресныйКлассификаторПовтИсп.НаименованияВладенийИСтроений();
		
		Для Каждого СведенияОДоме Из РезультатВебСервис.Данные Цикл

			ОписаниеДома = ОписаниеДомаИЗемельногоУчастка();

			ИзвлечьСтроенияВОписаниеДома(ОписаниеДома, СведенияОДоме);

			ОписаниеДома.ИдентификаторДома      = СведенияОДоме.id;
			ОписаниеДома.Индекс                 = Формат(СведенияОДоме.ZipCode, "ЧГ=0");
			ОписаниеДома.ОКТМО                  = Формат(СведенияОДоме.oktmo, "ЧГ=0");
			ОписаниеДома.ОКАТО                  = Формат(СведенияОДоме.okato, "ЧГ=0");
			ОписаниеДома.КодИФНСФЛ              = Формат(СведенияОДоме.ifnsFlCode, "ЧГ=0");
			ОписаниеДома.КодИФНСЮЛ              = Формат(СведенияОДоме.ifnsUlCode, "ЧГ=0");
			ОписаниеДома.КодУчасткаИФНСФЛ       = Формат(СведенияОДоме.ifnsFlAreaCode, "ЧГ=0");
			ОписаниеДома.КодУчасткаИФНСЮЛ       = Формат(СведенияОДоме.ifnsUlAreaCode, "ЧГ=0");
			ОписаниеДома.ЗагруженныеДанные      = Ложь;

			ДобавитьИнформациюОДоме(ВариантыДомов, ОписаниеДома, НаименованиеЗданийИСтроений, СтрокаПоиска);
		КонецЦикла;

	КонецЕсли;

	ВариантыДомов.Индексы.Добавить("ДомЧислом, Дом, ДополнительныйДом1, ДополнительныйДом2");
	ВариантыДомов.Сортировать("ДомЧислом, Дом, ДополнительныйДом2, ДополнительныйДом2");

	Возврат ВариантыДомов;

КонецФункции

// Возвращает список номеров земельных участков по идентификатору адресного объекта, поиск по подобию.
//
// Параметры:
//     ИдентификаторАдресногоОбъекта - УникальныйИдентификатор - родительский объект.
//     СтрокаПоиска - Строка - текст, отбора в списке земельных участков.
//     ПорцияПриПоиске - Число - кол-во получаемых вариантов за один запрос.
//
// Возвращаемое значение:
//     ТаблицаЗначений  -  найденные варианты.
//
Функция СписокЗемельныхУчастков(ИдентификаторАдресногоОбъекта, Знач СтрокаПоиска, ПорцияПриПоиске = 20) Экспорт

	ВариантыЗемельныхУчастков = Новый ТаблицаЗначений;
	ВариантыЗемельныхУчастков.Колонки.Добавить("Значение");
	ВариантыЗемельныхУчастков.Колонки.Добавить("Представление", ОбщегоНазначения.ОписаниеТипаСтрока(250));
	ВариантыЗемельныхУчастков.Колонки.Добавить("Идентификатор");

	Если СтрЗаканчиваетсяНа(СтрокаПоиска, "%") Тогда
		ТочноеСовпадение = Ложь;
		СтрокаПоиска     = Лев(СтрокаПоиска, СтрДлина(СтрокаПоиска) - 1);
	Иначе
		ТочноеСовпадение = Истина;
	КонецЕсли;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] Тогда

		СписокЗемельныхУчастковИзЗагруженныхСведений(ВариантыЗемельныхУчастков, ИдентификаторАдресногоОбъекта,
			СтрокаПоиска, ТочноеСовпадение);

	КонецЕсли;
	
	Если ВариантыЗемельныхУчастков.Количество() = 0 И ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина Тогда
		ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("select?parentId=%1&limit=%2&level=9&addressType=%3",
			Строка(ИдентификаторАдресногоОбъекта), Формат(ПорцияПриПоиске, "ЧГ=0"), 
			ТипАдресаДляВебСервиса(МуниципальныйАдрес()));
		Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
			ТекстGETЗапроса = ТекстGETЗапроса + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("&text=%1",
				СокрЛП(СтрокаПоиска));
		КонецЕсли;

		РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

		Если РезультатВебСервис.Отказ Тогда
			Возврат ВариантыЗемельныхУчастков;
		КонецЕсли;

		Для Каждого СведенияОДоме Из РезультатВебСервис.Данные Цикл

			ОписаниеУчастка = ОписаниеДомаИЗемельногоУчастка();

			ОписаниеУчастка.ИдентификаторДома      = СведенияОДоме.id;
			ОписаниеУчастка.НомерДома              = СведенияОДоме.steadNumber;
			ОписаниеУчастка.Индекс                 = Формат(СведенияОДоме.ZipCode, "ЧГ=0");
			ОписаниеУчастка.ОКТМО                  = Формат(СведенияОДоме.oktmo, "ЧГ=0");
			ОписаниеУчастка.ОКАТО                  = Формат(СведенияОДоме.okato, "ЧГ=0");
			ОписаниеУчастка.КодИФНСФЛ              = Формат(СведенияОДоме.ifnsFlCode, "ЧГ=0");
			ОписаниеУчастка.КодИФНСЮЛ              = Формат(СведенияОДоме.ifnsUlCode, "ЧГ=0");
			ОписаниеУчастка.КодУчасткаИФНСФЛ       = Формат(СведенияОДоме.ifnsFlAreaCode, "ЧГ=0");
			ОписаниеУчастка.КодУчасткаИФНСЮЛ       = Формат(СведенияОДоме.ifnsUlAreaCode, "ЧГ=0");

			НовыйУчасток = ВариантыЗемельныхУчастков.Добавить();
			НовыйУчасток.Значение = ОписаниеУчастка;
			НовыйУчасток.Представление = СведенияОДоме.steadNumber;
			НовыйУчасток.Идентификатор = СведенияОДоме.id;

		КонецЦикла;

	КонецЕсли;

	ВариантыЗемельныхУчастков.Сортировать("Представление");

	Возврат ВариантыЗемельныхУчастков;

КонецФункции

// Возвращает актуальные данные адресного объекта или ориентира с точностью доя подчиненного (без домов).
//
// Параметры:
//  СведенияОбАдресномОбъекте - Структура:
//    * ЗагруженныеДанные - Булево - признак, что источник адресных сведений загруженные в программу данные.
//    * Муниципальный     - Булево - признак, что адрес муниципальный.
//    * Идентификатор     - УникальныйИдентификатор - идентификатор адресного объекта или ориентира.
//    * Адрес             - Структура
// 
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ИсключатьГородИзМуниципальногоАдреса - Булево - если Ложь, то представление муниципального адреса включает город.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Данные                       - Структура - адрес.
//
Функция АктуальныеАдресныеСведения(СведенияОбАдресномОбъекте) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("Данные", Новый Структура);

	СтруктураОписанияОшибкиПоставщика(Результат);
	
	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	КлассификаторДоступен = ЗагруженныеАдресныеСведения.Получить("КлассификаторДоступен");
	Если СведенияОбАдресномОбъекте.Свойство("ЗагруженныеДанные") 
	   И ТипЗнч(СведенияОбАдресномОбъекте.ЗагруженныеДанные) = Тип("Булево") Тогда
		ЗагруженныеДанные = СведенияОбАдресномОбъекте.ЗагруженныеДанные;
	Иначе
		ЗагруженныеДанные = ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"]; // Если неизвестен источник, то сначала ищем в загруженные данных.
		СведенияОбАдресномОбъекте.Вставить("ЗагруженныеДанные", ЗагруженныеДанные);
	КонецЕсли;

	Если СведенияОбАдресномОбъекте.Свойство("Муниципальный") Тогда
		ЭтоМуниципальныйАдрес = СведенияОбАдресномОбъекте.Муниципальный;
	Иначе
		СведенияОбАдресномОбъекте.Вставить("Муниципальный", Истина);
		ЭтоМуниципальныйАдрес = Истина;
	КонецЕсли;
	
	Если ЗагруженныеДанные = Истина Тогда
		ЗаполнитьАдресныеСведенияИзЗагруженныхДанных(Результат.Данные, СведенияОбАдресномОбъекте);
	КонецЕсли;

	Если АдресПустой(Результат.Данные) Тогда

		Если Не КлассификаторДоступен Тогда
			Результат.Отказ = Истина;
			Возврат Результат;
		КонецЕсли;
		
		ЗаполнитьАктуальныеАдресныеСведенияСервис1С(Результат, СведенияОбАдресномОбъекте,
			ЭтоМуниципальныйАдрес);

		Если АдресПустой(Результат.Данные) Тогда
			Результат.Данные = ОписаниеНовойКонтактнойИнформации();
		КонецЕсли;

	КонецЕсли;

	Возврат Результат;

КонецФункции

// Проверяет данные на соответствие классификатору.
//
// Параметры:
//     Адреса - Массив - проверяемые адреса. Содержит структуры с полями:
//         * Адрес                             - ОбъектXDTO
//                                             - Строка - проверяемый адрес
//                                               ((http://www.v8.1c.ru/ssl/AddressSystem) АдресРФ) или его
//                                               XML-сериализация.
//         * ФорматАдреса - Строка - устарело. тип используемого классификатора для проверки.
// 
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Данные - Массив из Структура - результаты проверки. Индекс результата совпадает с индексом параметра Адреса:
//           ** Ошибки   - Массив из Структура - описание ошибок поиска в классификаторе. Состоит из структур с полями:
//               *** Ключ      - Строка - служебный идентификатор места ошибки - путь XPath в объекте XDTO.
//               *** Текст     - Строка - текст ошибки.
//               *** Подсказка - Строка - текст возможного исправления ошибки.
//           ** Варианты - Массив из Структура - содержит описание найденных вариантов. Каждый элемент - структура с полями:
//               *** Идентификатор    - УникальныйИдентификатор  - код классификатора объекта - варианта.
//               *** Индекс           - Число - почтовый индекс объекта - варианта.
//               *** КодКЛАДР         - Число - код КЛАДР ближайшего объекта.
//               *** OKATO            - Число - данные ФНС.
//               *** ОКТМО            - Число - данные ФНС.
//               *** КодИФНСФЛ        - Число - данные ФНС.
//               *** КодИФНСЮЛ        - Число - данные ФНС.
//               *** КодУчасткаИФНСФЛ - Число - данные ФНС.
//               *** КодУчасткаИФНСЮЛ - Число - данные ФНС.
//
Функция РезультатПроверкиАдресовПоКлассификатору(Адреса) Экспорт

	Результат = Новый Структура("Данные", Новый Массив);
	СтруктураОписанияОшибкиПоставщика(Результат);
	
	// Приводим типы
	АдресаВебСервис         = Новый Соответствие;
	АдресаЗагруженныеДанные = Новый Соответствие;
	НаборАдресов            = Новый Соответствие;

	Если ТипЗнч(Адреса) <> Тип("Массив") Тогда

		Если ТипЗнч(Адреса) <> Тип("Структура") Или Не Адреса.Свойство("Area") Тогда
			Возврат Результат;
		КонецЕсли;

		Адреса = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Адреса);
	КонецЕсли;

	Для ПорядковыйНомер = 0 По Адреса.ВГраница() Цикл
		НаборАдресов.Вставить(ПорядковыйНомер, Адреса[ПорядковыйНомер].Адрес);
	КонецЦикла;

	ПервичнаяПроверка = ПервичнаяПроверкаАдресов(НаборАдресов);

	Для Каждого АдресПроверки Из ПервичнаяПроверка.Адреса Цикл
		УникальныйКлюч  = АдресПроверки.Ключ;
		СведенияОАдресе = АдресПроверки.Значение;
		Адрес           = НаборАдресов[УникальныйКлюч];

		Если СведенияОАдресе.АдресПроверен И Не СведенияОАдресе.АдресКорректный Тогда
			Результат.Данные.Добавить(СведенияОАдресе);
			Продолжить;
		КонецЕсли;

		ЗагруженныеСведения = СведенияОРегионе(Адрес.area, Адрес.areaType);

		Если ЗагруженныеСведения.Загружен Тогда
			АдресаЗагруженныеДанные.Вставить(УникальныйКлюч, Адрес);
		Иначе
			УстановкаТипаКузбассКемеровскойОбластиКакВГАР(Адрес);
			АдресаВебСервис.Вставить(УникальныйКлюч, Адрес);
		КонецЕсли;
	КонецЦикла;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();
	РезультатЗагруженныеДанные = Новый Соответствие;
	РезультатВебСервис         = Новый Соответствие;

	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] И АдресаЗагруженныеДанные.Количество() > 0 Тогда
		РезультатЗагруженныеДанные = ПроверитьАдресаПоКлассификатору(АдресаЗагруженныеДанные, Истина);
	КонецЕсли;

	Если ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина И АдресаВебСервис.Количество() > 0 Тогда
		ДанныеИзВебСервиса = ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(АдресаВебСервис, Ложь);
		Если Не ДанныеИзВебСервиса.Отказ Тогда
			РезультатВебСервис = ДанныеИзВебСервиса.Данные;
		КонецЕсли;
	КонецЕсли;

	ТаблицаДляСортировки = Новый ТаблицаЗначений;
	ТаблицаДляСортировки.Колонки.Добавить("ПорядковыйНомер", ОбщегоНазначения.ОписаниеТипаЧисло(10));
	ТаблицаДляСортировки.Колонки.Добавить("Адрес");

	Для Каждого АдресВНаборе Из НаборАдресов Цикл
		НоваяСтрока = ТаблицаДляСортировки.Добавить();
		НоваяСтрока.ПорядковыйНомер = АдресВНаборе.Ключ;
		НоваяСтрока.Адрес = АдресВНаборе.Значение;
	КонецЦикла;

	ТаблицаДляСортировки.Сортировать("ПорядковыйНомер");

	Для Каждого Строка Из ТаблицаДляСортировки Цикл

		РезультатПроверки = РезультатЗагруженныеДанные[Строка.ПорядковыйНомер];
		Если РезультатПроверки = Неопределено Тогда
			РезультатПроверки = РезультатВебСервис[Строка.ПорядковыйНомер];
			Если РезультатПроверки = Неопределено Тогда
				РезультатПроверки = Новый Структура;
				РезультатПроверки.Вставить("id", Строка.ПорядковыйНомер);
				РезультатПроверки.Вставить("АдресПроверен", Ложь);
				РезультатПроверки.Вставить("Варианты", Новый Массив);
				РезультатПроверки.Вставить("Ошибки", Новый Массив);
			КонецЕсли;
		КонецЕсли;

		Результат.Данные.Добавить(РезультатПроверки);
	КонецЦикла;

	Возврат Результат;

КонецФункции

// Параметры:
//  НаборАдресов - Соответствие
//  ПроверятьУстареваниеАдресов - Булево
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - Число
//   * Значение - см. РезультатПроверкиАдреса
// 
Функция ПроверкаАдресов(Знач НаборАдресов, ПроверятьУстареваниеАдресов = Ложь) Экспорт

	Результат = Новый Соответствие;

	РезультатыЗагруженныеДанные  = Новый Соответствие;
	РезультатыВебСервис         = Новый Соответствие;

	АдресаВебСервис         = Новый Соответствие;
	АдресаЗагруженныеДанные = Новый Соответствие;

	ПервичнаяПроверка = ПервичнаяПроверкаАдресов(НаборАдресов);

	Для Каждого АдресПроверки Из ПервичнаяПроверка.Адреса Цикл
		УникальныйКлюч  = АдресПроверки.Ключ;
		СведенияОАдресе = АдресПроверки.Значение;
		Адрес           = НаборАдресов[УникальныйКлюч];

		Если СведенияОАдресе.АдресПроверен И Не СведенияОАдресе.АдресКорректный Тогда
			Результат.Вставить(УникальныйКлюч, СведенияОАдресе);
			Продолжить;
		КонецЕсли;

		ЗагруженныеСведения = СведенияОРегионе(Адрес.Area, Адрес.AreaType);

		Если ЗагруженныеСведения.Загружен Тогда
			АдресаЗагруженныеДанные.Вставить(УникальныйКлюч, Адрес);
		Иначе
			АдресаВебСервис.Вставить(УникальныйКлюч, Адрес);
		КонецЕсли;
	КонецЦикла;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] И АдресаЗагруженныеДанные.Количество() > 0 Тогда
		РезультатыЗагруженныеДанные = ПроверитьАдресаПоКлассификатору(АдресаЗагруженныеДанные,
			ПроверятьУстареваниеАдресов);

		Для Каждого РезультатЗагруженныеДанные Из РезультатыЗагруженныеДанные Цикл
			Результат.Вставить(РезультатЗагруженныеДанные.Ключ, РезультатЗагруженныеДанные.Значение);
		КонецЦикла;

	КонецЕсли;

	Если ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина И АдресаВебСервис.Количество() > 0 Тогда
		ДанныеИзВебСервиса = ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(АдресаВебСервис);
		Если Не ДанныеИзВебСервиса.Отказ Тогда
			РезультатыВебСервис = ДанныеИзВебСервиса.Данные;
		КонецЕсли;

		Для Каждого РезультатВебСервис Из РезультатыВебСервис Цикл
			Результат.Вставить(РезультатВебСервис.Ключ, РезультатВебСервис.Значение);
		КонецЦикла;

	КонецЕсли;

	Возврат Результат;

КонецФункции

// Преобразует формат из XML в JSON
//
Функция КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, Представление = "") Экспорт

	Результат = ОписаниеНовойКонтактнойИнформации();

	НаименованиеСтраны = "";

	Если ТипЗнч(КонтактнаяИнформация) = Тип("Строка") Тогда
		Если ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
			XDTOАдрес = ДесериализацияАдресаXDTO(КонтактнаяИнформация);
			Если XDTOАдрес.Свойства().Получить("Представление") <> Неопределено Тогда
				Результат.Value   = XDTOАдрес.Представление;
			КонецЕсли;
			Если XDTOАдрес.Свойства().Получить("Комментарий") <> Неопределено 
			   И ТипЗнч(XDTOАдрес.Комментарий) = Тип("Строка") Тогда
				Результат.Comment = XDTOАдрес.Комментарий;
			КонецЕсли;
		ИначеЕсли ЭтоКонтактнаяИнформацияВJSON(КонтактнаяИнформация) Тогда
			АдресИзJSON = JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформация);
			ЗаполнитьЗначенияСвойств(Результат, АдресИзJSON);
			УстановитьИдентификаторыАдреса(Результат);
			Возврат Результат;
		Иначе
			Возврат Результат;
		КонецЕсли;
	Иначе
		Возврат Результат;
	КонецЕсли;

	ПространствоИмен = ПространствоИмен();
	Состав = XDTOАдрес.Состав;

	Если Состав = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	XDTOТип = Состав.Тип();

	Если XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") 
	   Или XDTOТип = ФабрикаXDTO.Тип("http://www.v8.1c.ru/ssl/contactinfo", "Адрес") Тогда

		Если Состав.Свойства().Получить("Страна") <> Неопределено И ЗначениеЗаполнено(Состав.Страна) Тогда
			НаименованиеСтраны = Состав.Страна;
		Иначе
			НаименованиеСтраны = ОсновнаяСтрана();
		КонецЕсли;

		АдресРФ = Состав.Состав;

	ИначеЕсли XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен(), "АдресРФ") Тогда
		АдресРФ = Состав;
	Иначе
		Возврат Результат;
	КонецЕсли;

	Если АдресРФ = Неопределено Тогда
		Возврат Результат;
	ИначеЕсли ТипЗнч(АдресРФ) = Тип("Строка") Тогда
		
		Если СтрЧислоВхождений(АдресРФ, ",") = 9 Тогда
			
			Результат.AddressType = АдминистративноТерриториальныйАдрес();

			ЧастиАдреса = СтрРазделить(АдресРФ, ",");
			Результат.ZIPCode = ЧастиАдреса[1];

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[2]);
			Результат.Area     = НаименованиеИТипОбъекта.Наименование;
			Результат.AreaType = НаименованиеИТипОбъекта.Сокращение;
			ОбновитьСписокУровней(Результат, "area", ЗначениеЗаполнено(Результат["area"]));

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[3]);
			Результат.District     = НаименованиеИТипОбъекта.Наименование;
			Результат.DistrictType = НаименованиеИТипОбъекта.Сокращение; 
			ОбновитьСписокУровней(Результат, "district", ЗначениеЗаполнено(Результат["district"]));

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[4]);
			Результат.City         = НаименованиеИТипОбъекта.Наименование;
			Результат.CityType     = НаименованиеИТипОбъекта.Сокращение;
			ОбновитьСписокУровней(Результат, "city", ЗначениеЗаполнено(Результат["city"]));

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[5]);
			Результат.Locality     = НаименованиеИТипОбъекта.Наименование;
			Результат.LocalityType = НаименованиеИТипОбъекта.Сокращение; 
			ОбновитьСписокУровней(Результат, "locality", ЗначениеЗаполнено(Результат["locality"]));

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[6]);
			Результат.Street       = НаименованиеИТипОбъекта.Наименование;
			Результат.StreetType   = НаименованиеИТипОбъекта.Сокращение;
			ОбновитьСписокУровней(Результат, "street", ЗначениеЗаполнено(Результат["street"]));

			НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[7]);
			Результат.HouseNumber  = НаименованиеИТипОбъекта.Сокращение;
			Результат.HouseType    = НаименованиеИТипОбъекта.Наименование;
			ОбновитьСписокУровней(Результат, "house", ЗначениеЗаполнено(Результат["HouseNumber"]));

			Если ЗначениеЗаполнено(ЧастиАдреса[8]) Тогда
				НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[8]);
				Результат.Buildings.Добавить(ЗначениеСтроенияИлиПомещения(НаименованиеИТипОбъекта.Сокращение,
					НаименованиеИТипОбъекта.Наименование));
				ОбновитьСписокУровней(Результат, "house", Истина);
			КонецЕсли;

			Если ЗначениеЗаполнено(ЧастиАдреса[9]) Тогда
				НаименованиеИТипОбъекта = НаименованиеИТипОбъекта(ЧастиАдреса[9]);
				Результат.Apartments.Добавить(ЗначениеСтроенияИлиПомещения(
				НаименованиеИТипОбъекта.Сокращение, НаименованиеИТипОбъекта.Наименование));
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе

		Если ЗначениеЗаполнено(АдресРФ.Адрес_по_документу) Тогда
			Результат.AddressType = АдресВСвободнойФорме();
		Иначе
			Результат.AddressType = АдминистративноТерриториальныйАдрес();
		КонецЕсли;

		Результат.Country = НаименованиеСтраны;
		Результат.ZIPCode = ПочтовыйИндексАдреса(АдресРФ);
		Результат.oktmo = Формат(АдресРФ.ОКТМО, "ЧГ=0");
		Результат.okato = Формат(АдресРФ.ОКАТО, "ЧГ=0");

		СубъектРФ = НаименованиеИТипОбъекта(АдаптацияНазванияРегиона(АдресРФ.СубъектРФ));
		Результат.Area     = Строка(СубъектРФ.Наименование);
		Результат.AreaType = Строка(СубъектРФ.ТипОбъекта);
		ОбновитьСписокУровней(Результат, "area", ЗначениеЗаполнено(Результат["area"]));

		РайонАдреса = НаименованиеИТипОбъекта(РайонАдреса(АдресРФ));
		Результат.District     = Строка(РайонАдреса.Наименование);
		Результат.DistrictType = Строка(РайонАдреса.ТипОбъекта);
		ОбновитьСписокУровней(Результат, "district", ЗначениеЗаполнено(Результат["district"]));
		
		Город = НаименованиеИТипОбъекта(АдресРФ.Город);
		Результат.City     = Строка(Город.Наименование);
		Результат.CityType = Строка(Город.ТипОбъекта);
		ОбновитьСписокУровней(Результат, "city", ЗначениеЗаполнено(Результат["city"]));
		
		НаселПункт = НаименованиеИТипОбъекта(АдресРФ.НаселПункт);
		Результат.Locality     = Строка(НаселПункт.Наименование);
		Результат.LocalityType = Строка(НаселПункт.ТипОбъекта);
		ОбновитьСписокУровней(Результат, "locality", ЗначениеЗаполнено(Результат["locality"]));
		
		ВнутригРайон = НаименованиеИТипОбъекта(АдресРФ.ВнутригРайон);
		Результат.CityDistrict     = Строка(ВнутригРайон.Наименование);
		Результат.CityDistrictType = Строка(ВнутригРайон.ТипОбъекта);
		
		ЗначениеДополнительныхЭлементов = ЗначениеДополнительныхЭлементов(АдресРФ);
		Если ЗначениеЗаполнено(ЗначениеДополнительныхЭлементов.ДополнительныйЭлемент) Тогда
			ДополнительныйЭлемент = НаименованиеИТипОбъекта(ЗначениеДополнительныхЭлементов.ДополнительныйЭлемент);
			Результат.Territory     = Строка(ДополнительныйЭлемент.Наименование);
			Результат.TerritoryType = Строка(ДополнительныйЭлемент.ТипОбъекта);
			ОбновитьСписокУровней(Результат, "territory", ЗначениеЗаполнено(Результат["territory"]));
		КонецЕсли;
		
		Улица = НаименованиеИТипОбъекта(АдресРФ.Улица);
		Результат.Street     = Строка(Улица.Наименование);
		Результат.StreetType = Строка(Улица.ТипОбъекта);
		ОбновитьСписокУровней(Результат, "street", ЗначениеЗаполнено(Результат["street"]));
		
		Если ЗначениеЗаполнено(ЗначениеДополнительныхЭлементов.ПодчиненныйЭлемент) Тогда
			ПодчиненныйЭлемент = НаименованиеИТипОбъекта(ЗначениеДополнительныхЭлементов.ПодчиненныйЭлемент);
			Результат.Street     = Строка(ПодчиненныйЭлемент.Наименование);
			Результат.StreetType = Строка(ПодчиненныйЭлемент.ТипОбъекта);
			ОбновитьСписокУровней(Результат, "street", ЗначениеЗаполнено(Результат["street"]));
		КонецЕсли;
		
		ЗданияИПомещения = ЗданияИПомещенияАдреса(АдресРФ);
		АдресСодержитДома = Ложь;
		Для Каждого Здание Из ЗданияИПомещения.Здания Цикл
			Если Здание.Вид = 1 Тогда
				Результат.HouseType = Здание.Тип;
				Результат.HouseNumber = Здание.Значение;
			Иначе
				Результат.Buildings.Добавить(ЗначениеСтроенияИлиПомещения(Здание.Тип, Здание.Значение));
			КонецЕсли;
			АдресСодержитДома = Истина;
		КонецЦикла;
		
		ОбновитьСписокУровней(Результат, "house", АдресСодержитДома);
		
		Для Каждого Помещение Из ЗданияИПомещения.Помещения Цикл
			Результат.Apartments.Добавить(ЗначениеСтроенияИлиПомещения(Помещение.Тип, Помещение.Значение));
		КонецЦикла;
	КонецЕсли;

	УстановкаТипаКузбассКемеровскойОбластиКакВГАР(Результат); // обратная совместимость
	УстановитьИдентификаторыАдреса(Результат);

	Возврат Результат;

КонецФункции

// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//    * Ключ - Число
//    * Значение - Структура:
//      ** Отказ - Булево - поставщик не доступен.
//      ** ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ=Ложь.
//      ** КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ=Ложь.
//      ** Данные                       - Массив из Структура - результаты проверки. где:
//         *** Ошибки   - Массив из Структура  - описание ошибок поиска в классификаторе. Состоит из структур с полями:
//            **** Ключ      - Строка - служебный идентификатор места ошибки - путь XPath в объекте XDTO.
//            **** Текст     - Строка - текст ошибки.
//            **** Подсказка - Строка - текст возможного исправления ошибки.
//         *** Варианты - Массив из Структура  - содержит описание найденных вариантов. Каждый элемент структура с полями:
//            **** Идентификатор    - УникальныйИдентификатор  - код классификатора объекта - варианта.
//            **** Индекс           - Число - почтовый индекс объекта - варианта.
//            **** КодКЛАДР         - Число - код КЛАДР ближайшего объекта.
//            **** OKATO            - Число - данные ФНС.
//            **** ОКТМО            - Число - данные ФНС.
//            **** КодИФНСФЛ        - Число - данные ФНС.
//            **** КодИФНСЮЛ        - Число - данные ФНС.
//            **** КодУчасткаИФНСФЛ - Число - данные ФНС.
//            **** КодУчасткаИФНСЮЛ - Число - данные ФНС.
//
Функция РезультатПроверкиАдресов(НаборАдресов, ПроверятьУстареваниеАдресов = Ложь) Экспорт

	АдресаВебСервис         = Новый Соответствие;
	АдресаЗагруженныеДанные = Новый Соответствие;

	РезультатыВебСервис        = Новый Соответствие;
	РезультатПроверки = Новый Соответствие;

	ПервичнаяПроверка = ПервичнаяПроверкаАдресов(НаборАдресов);

	Для Каждого АдресПроверки Из ПервичнаяПроверка.Адреса Цикл
		УникальныйКлюч  = АдресПроверки.Ключ;
		СведенияОАдресе = АдресПроверки.Значение;
		Адрес           = НаборАдресов[УникальныйКлюч];

		Если СведенияОАдресе.АдресПроверен Тогда
			РезультатПроверки.Вставить(УникальныйКлюч, СведенияОАдресе);
			Продолжить;
		КонецЕсли;

		ЗагруженныеСведения = СведенияОРегионе(Адрес.area, Адрес.areaType);

		Если ЗагруженныеСведения.Загружен Тогда
			АдресаЗагруженныеДанные.Вставить(УникальныйКлюч, Адрес);
		Иначе
			АдресаВебСервис.Вставить(УникальныйКлюч, Адрес);
		КонецЕсли;
	КонецЦикла;

	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] И АдресаЗагруженныеДанные.Количество() > 0 Тогда
		
		РезультатыПоКлассификатору = ПроверитьАдресаПоКлассификатору(АдресаЗагруженныеДанные, ПроверятьУстареваниеАдресов); 
		Для каждого РезультатПоКлассификатору Из РезультатыПоКлассификатору Цикл
			РезультатПроверки.Вставить(РезультатПоКлассификатору.Ключ, РезультатПоКлассификатору.Значение);
		КонецЦикла;
		
	КонецЕсли;
	
	Если ЗагруженныеАдресныеСведения["КлассификаторДоступен"] = Истина И АдресаВебСервис.Количество() > 0 Тогда
		ДанныеИзВебСервиса = ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(АдресаВебСервис, Ложь);
		Если Не ДанныеИзВебСервиса.Отказ Тогда
			РезультатыВебСервис = ДанныеИзВебСервиса.Данные;
		КонецЕсли;
	КонецЕсли;

	Для Каждого РезультатВебСервис Из РезультатыВебСервис Цикл
		РезультатПроверки.Вставить(РезультатВебСервис.Ключ, РезультатВебСервис.Значение);
	КонецЦикла;

	Возврат РезультатПроверки;

КонецФункции

// Возвращает соответствие полных наименований адресных объектов и их сокращения.
//
// Параметры:
//  НаименованияАдресныхОбъектов - Массив - полные наименования адресных объектов. Если передан пустой массив,
//                                          то будут возвращен полный список наименований и сокращений.
//
// Возвращаемое значение:
//  Соответствие - соответствие найденных полных наименований адресных объектов их сокращениям.
//
Функция СокращенияАдресныхОбъектов(НаименованияАдресныхОбъектов = Неопределено) Экспорт

	Результат = Новый Соответствие;

	Источник = ИсточникДанныхАдресногоКлассификатора();
	Если ПустаяСтрока(Источник) Тогда

		ТаблицаАдресныхСокращений = ТаблицаАдресныхСокращений(НаименованияАдресныхОбъектов);

		Для Каждого СтрокаТаблицы Из ТаблицаАдресныхСокращений Цикл
			Результат.Вставить(ВРег(СтрокаТаблицы.Наименование), СтрокаТаблицы.Сокращение);
		КонецЦикла;

		Если Результат.Количество() > 0 Тогда
			Возврат Результат;
		КонецЕсли;
	КонецЕсли;
	
	// Веб сервис 1С или классификатор не загружен, получаем данные о сокращениях из макета.
	ТаблицаАдресныхСокращений = АдресныеСокращения();

	Если ТипЗнч(НаименованияАдресныхОбъектов) = Тип("Массив") И НаименованияАдресныхОбъектов.Количество() > 0 Тогда
		Для Каждого ПолноеНаименование Из НаименованияАдресныхОбъектов Цикл
			СтрокаТаблицы = ТаблицаАдресныхСокращений.Найти(ПерваяБукваЗаглавная(ПолноеНаименование), "Наименование");
			Если СтрокаТаблицы <> Неопределено Тогда
				Результат.Вставить(ВРег(СтрокаТаблицы.Наименование), СтрокаТаблицы.Сокращение);
			КонецЕсли;
		КонецЦикла;
	Иначе
		Для Каждого СтрокаТаблицы Из ТаблицаАдресныхСокращений Цикл
			Результат.Вставить(ВРег(СтрокаТаблицы.Наименование), СтрокаТаблицы.Сокращение);
		КонецЦикла;
	КонецЕсли;

	Возврат Результат;

КонецФункции

Функция АдресныеСокращения() Экспорт

	Возврат РегистрыСведений.АдресныеОбъекты.АдресныеСокращения();

КонецФункции

Функция АдресныеСокращенияПриказМинфинаРФ171н() Экспорт

	Возврат АдресныйКлассификаторПовтИсп.АдресныеСокращенияПриказМинфинаРФ171н();

КонецФункции

// Обратная совместимость
//
Функция КраткоеНаписаниеМуниципальныхРайонов(Наименование, ТипОбъекта) Экспорт

	МуниципальныеРайоны = АдресныйКлассификаторПовтИсп.МуниципальныеРайоны();
	ВырезаемаяПодстрока = МуниципальныеРайоны.Получить(ВРег(ТипОбъекта));

	Если ЗначениеЗаполнено(ВырезаемаяПодстрока) Тогда
		Наименование = ОбрезанноеНазвание(Наименование, ВырезаемаяПодстрока);
	КонецЕсли;

	Возврат Наименование;

КонецФункции

// Обратная совместимость
// 
// Параметры:
//  Наименование - Строка 
//  Сокращение - Строка
// 
// Возвращаемое значение:
//  Строка - краткое написание поселений
//
Функция КраткоеНаписаниеПоселений(Знач Наименование, Сокращение) Экспорт

	Поселения = АдресныйКлассификаторПовтИсп.Поселения();
	ВырезаемаяПодстрока = Поселения.Получить(ВРег(Сокращение));

	Если ЗначениеЗаполнено(ВырезаемаяПодстрока) Тогда
		Наименование = ОбрезанноеНазвание(Наименование, ВырезаемаяПодстрока);
	КонецЕсли;

	Возврат Наименование;

КонецФункции

// Определение кодов ОКАТО, ОКТМО, налоговых инспекций ФНС и др. адреса.
//
// Параметры:
//  Адрес    - Строка - адрес в формате JSON или XML
//  Источник - Строка - источник получения кодов адреса, Варианты: "Сервис1С", "ЗагруженныеДанные".
//                      Если не указан, то код сначала ищется в загруженных данных и если не найден, то в веб-сервисе.
//
// Возвращаемое значение:
//  Структура - коды адреса.
//
Функция КодыАдреса(Знач Адрес, Источник = Неопределено) Экспорт

	Если ЭтоКонтактнаяИнформацияВXML(Адрес) Тогда
		АдресСтруктура = КонтактнаяИнформацияВСтруктуруJSON(Адрес);
	ИначеЕсли ЭтоКонтактнаяИнформацияВJSON(Адрес) Тогда
		АдресСтруктура = JSONВКонтактнуюИнформациюПоПолям(Адрес);
	ИначеЕсли ЭтоКонтактнаяИнформацияВФорматеКлючЗначение(Адрес) Тогда
		АдресСтруктура = КонтактнаяИнформацияВФорматеКлючЗначениеВJSON(Адрес);
	Иначе
		ОписаниеПричиныОшибки = НСтр("ru = 'Передано недопустимое значение адреса в функцию получения кодов адреса'");
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение, , Адрес,
			ОписаниеПричиныОшибки);
		Возврат КонструкторКодовАдреса();
	КонецЕсли;

	ИдентификаторАдресногоОбъекта = "";
	Если ТипЗнч(АдресСтруктура) = Тип("Структура") 
	   И АдресСтруктура.Свойство("ID") И ЗначениеЗаполнено(АдресСтруктура.ID) Тогда
		ИдентификаторАдресногоОбъекта = АдресСтруктура.ID;
	КонецЕсли;

	Возврат КодыАдресаИКодыКЛАДР(АдресСтруктура, ИдентификаторАдресногоОбъекта, Источник)

КонецФункции

// Определение кодов КЛАДР и ОКАТО, ОКТМО, налоговых инспекций ФНС и др. адреса.
//
// Параметры:
//  Адрес    - Строка - адрес в формате XML или структура с полями адреса.
//  ИдентификаторАдресногоОбъекта - Строка - идентификатор адреса.
//  Источник - Строка - источник получения кодов адреса, Варианты: "Сервис1С", "ЗагруженныеДанные".
// Возвращаемое значение:
//  Структура - содержит 2 структуры: Коды адреса и Коды КЛАДР.
//
Функция КодыАдресаИКодыКЛАДР(Знач Адрес, Знач ИдентификаторАдресногоОбъекта = "", Источник = Неопределено) Экспорт

	Результат = КонструкторКодовАдреса();

	КодКЛАДРЗаполнены = Ложь;
	ЗагруженныеАдресныеСведения = АдресныйКлассификаторПовтИсп.СведенияОЗагрузкеСубъектовРФ();

	Если ПустаяСтрока(ИдентификаторАдресногоОбъекта) Тогда
		Если Не ЗначениеЗаполнено(Адрес.ID) Тогда
			УстановитьИдентификаторыАдреса(Адрес, Источник);
		КонецЕсли;
		ИдентификаторАдресногоОбъекта = Адрес.ID;
	КонецЕсли;

	Результат.КодыАдреса.Идентификатор = ИдентификаторАдресногоОбъекта;

	Если ЗагруженныеАдресныеСведения["ИспользоватьЗагруженные"] И Источник <> "Сервис1С" Тогда

		ОсновныеКодыЗаполнены = Ложь;
		// Основные коды 
		Если ЗаполненыВсеИдентификаторыОбъекта(Адрес) И ЗначениеЗаполнено(ИдентификаторАдресногоОбъекта) Тогда
			
			СведенияОДоме = СведенияОДоме();
			ИзвлечьСтроенияВОписаниеДома(СведенияОДоме, Адрес);
			
			ОсновныеКодыЗаполнены = ЗаполнитьКодыАдреса(Результат.КодыАдреса, ИдентификаторАдресногоОбъекта,
				СведенияОДоме);

		КонецЕсли;

		КодКЛАДРЗаполнены = Ложь;
		Если ЗаполненыВсеИдентификаторыОбъекта(Адрес) И ЗначениеЗаполнено(ИдентификаторАдресногоОбъекта) Тогда
			// Код КЛАДР 
			Запрос = Новый Запрос;
			Запрос.Текст = 
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	АдресныеОбъекты.КодКЛАДР КАК КодКЛАДР
			|ИЗ
			|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
			|ГДЕ
			|	АдресныеОбъекты.Идентификатор = &Идентификатор";
			
			Запрос.УстановитьПараметр("Идентификатор", ИдентификаторАдресногоОбъекта);
			
			РезультатЗапроса = Запрос.Выполнить();

			Если Не РезультатЗапроса.Пустой() Тогда

				КодКЛАДР = КодКЛАДРСтрокой(РезультатЗапроса.Выгрузить()[0].КодКЛАДР);
				Результат.КодыАдреса.КодКЛАДР = КодКЛАДР;

				СформироватьКодыКЛАДР(КодКЛАДР, Адрес, Результат.КодыКЛАДР);
				КодКЛАДРЗаполнены = Истина;

			КонецЕсли;
		КонецЕсли;

		Если КодКЛАДРЗаполнены И ОсновныеКодыЗаполнены Тогда

			Возврат Результат;

		КонецЕсли;

	КонецЕсли;
	
	// Получаем коды из веб-сервиса.
	Если ЗагруженныеАдресныеСведения["КлассификаторДоступен"] Или Источник = "Сервис1С" Тогда

		Адреса = Новый Соответствие;
		Адреса.Вставить(1, Адрес);

		РезультатВебСервис = ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(Адреса);

		Если Не РезультатВебСервис.Отказ Тогда

			АдресПослеПроверки = РезультатВебСервис.Данные.Получить(1);
			Если Не АдресПослеПроверки.АдресКорректный Или АдресПослеПроверки.Варианты.Количество() = 0 Тогда
				Возврат Результат;
			КонецЕсли;

			Сведения = АдресПослеПроверки.Варианты[0];
			Если Не КодКЛАДРЗаполнены Тогда
				Результат.КодыАдреса.КодКЛАДР = Сведения.codeKLADR;
				СформироватьКодыКЛАДР(Результат.КодыАдреса.КодКЛАДР, Адрес, Результат.КодыКЛАДР);
			КонецЕсли;

			Результат.КодыАдреса.КодКЛАДР = Сведения.codeKLADR;
			Результат.КодыАдреса.Идентификатор = ИдентификаторАдресногоОбъекта(Сведения);
			Результат.КодыАдреса.ИдентификаторДома = ?(ЗначениеЗаполнено(Сведения.houseId), Сведения.houseId, "");
			Результат.КодыАдреса.ОКАТО                  = Сведения.okato;
			Результат.КодыАдреса.ОКТМО                  = Сведения.oktmo;

			Результат.КодыАдреса.КодИФНСФЛ              = Сведения.ifnsFlCode;
			Результат.КодыАдреса.КодИФНСЮЛ              = Сведения.ifnsUlCode;
			Результат.КодыАдреса.КодУчасткаИФНСФЛ       = Сведения.ifnsFlAreaCode;
			Результат.КодыАдреса.КодУчасткаИФНСЮЛ       = Сведения.ifnsUlAreaCode;
			
			// Свойство присутствует только в новой версии веб-сервиса адресов.
			Если Сведения.Свойство("oktmoBudget") Тогда
				Результат.КодыАдреса.ОКТМОБюджетополучателя = Сведения.oktmoBudget;
			КонецЕсли;

		КонецЕсли;

	КонецЕсли;

	Возврат Результат;

КонецФункции

// Полные наименования сокращений.
//
// Параметры:
//  СоответствиеСокращений - Соответствие - сокращения адреса.
//
Процедура ПолныеНаименованияСокращений(СоответствиеСокращений) Экспорт

	СписокСокращений   = АдресныйКлассификаторПовтИсп.СписокСокращений();
	АдресныеСокращения = АдресныеСокращения();

	Для Каждого ОписаниеСокращения Из СоответствиеСокращений Цикл

		Если ПустаяСтрока(ОписаниеСокращения.Значение) Тогда
			Продолжить;
		КонецЕсли;

		ПолноеНаименование = Строка(СписокСокращений.Получить(Строка(ОписаниеСокращения.Ключ)
			+ ОписаниеСокращения.Значение));
		Если ЗначениеЗаполнено(ПолноеНаименование) Тогда
			СоответствиеСокращений[ОписаниеСокращения.Ключ] = ПолноеНаименование;
		Иначе

			Отбор = Новый Структура;
			Отбор.Вставить("Уровень", ОписаниеСокращения.Ключ);
			Отбор.Вставить("Сокращение", ОписаниеСокращения.Значение);
			НайденныеСокращения = АдресныеСокращения.НайтиСтроки(Отбор);
			Если НайденныеСокращения.Количество() > 0 Тогда
				СоответствиеСокращений[ОписаниеСокращения.Ключ] = НайденныеСокращения[0].Наименование;
			КонецЕсли;

		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

// Проверяет наличие записей о регионах в регистре сведений АдресныеОбъекты и заполняет их в случае отсутствия.
// 
// Возвращаемое значение:
//  Булево
//
Функция ПроверитьНачальноеЗаполнение() Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	АдресныеОбъекты.Уровень
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|ГДЕ
	|	АдресныеОбъекты.Уровень = 1";

	РезультатЗапроса = Запрос.Выполнить().Выгрузить();

	Если РезультатЗапроса.Количество() = 0 Тогда
		Если ПравоДоступа("Изменение", Метаданные.РегистрыСведений.АдресныеОбъекты) Тогда
			ВыполнитьНачальноеЗаполнение();
		Иначе
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;

	Возврат Истина;

КонецФункции

// Возвращает код региона и проверяет наличие загруженных адресных сведений по региону.
// 
// Параметры:
//  НаименованиеРегиона - Строка
//  ТипОбъекта - Строка
// 
// Возвращаемое значение:
//   см. АдресныйКлассификаторПовтИсп.СведенияОРегионе
//
Функция СведенияОРегионе(НаименованиеРегиона, ТипОбъекта) Экспорт

	Результат = АдресныйКлассификаторПовтИсп.СведенияОРегионе(НаименованиеРегиона, ТипОбъекта);
	Возврат Результат;

КонецФункции

// Возвращает информацию о состоянии загруженности регионов.
// 
// Возвращаемое значение:
//  ТаблицаЗначений - описание состояния. Содержит колонки::
//   * КодСубъектаРФ - Число - код региона.
//   * Идентификатор - УникальныйИдентификатор - идентификатор региона.
//   * Представление - Строка - полное наименование региона.
//   * Загружено - Булево - Истина, если классификатор по данному региону сейчас загружен.
//   * ДатаВерсии - Дата - UTC версия загруженных данных.
//
Функция СведенияОЗагрузкеСубъектовРФ() Экспорт

	Классификатор = РегистрыСведений.АдресныеОбъекты.КлассификаторСубъектовРФ();

	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	Параметр.Наименование КАК Наименование,
	|	Параметр.ТипОбъекта КАК ТипОбъекта,
	|	Параметр.ПолноеНаименование КАК ПолноеНаименование,
	|	Параметр.ОКТМО КАК ОКТМО,
	|	Параметр.КодСубъектаРФ КАК КодСубъектаРФ
	|ПОМЕСТИТЬ Классификатор
	|ИЗ
	|	&Классификатор КАК Параметр
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	Классификатор.Наименование КАК Наименование,
	|	ЕСТЬNULL(СлужебныеАдресныеСведения.Значение, Классификатор.ПолноеНаименование) КАК Представление,
	|	Классификатор.ТипОбъекта КАК ТипОбъекта,
	|	Классификатор.КодСубъектаРФ КАК КодСубъектаРФ,
	|	Классификатор.ОКТМО КАК ОКТМО,
	|	ЗагруженныеВерсииАдресныхСведений.Версия КАК Версия,
	|	ЕСТЬNULL(ЗагруженныеВерсииАдресныхСведений.ДатаВерсии, ДАТАВРЕМЯ(1, 1, 1, 1, 1, 1)) КАК ДатаВерсии,
	|	ЕСТЬNULL(ЗагруженныеВерсииАдресныхСведений.ДатаЗагрузки, ДАТАВРЕМЯ(1, 1, 1, 1, 1, 1)) КАК ДатаЗагрузки,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	НЕ ЗагруженныеВерсииАдресныхСведений.Версия ЕСТЬ NULL КАК Загружено,
	|	ДОБАВИТЬКДАТЕ(ЗагруженныеВерсииАдресныхСведений.ДатаЗагрузки, МЕСЯЦ, 1) < &ТекущаяДата КАК Устарело
	|	ИЗ
	|	Классификатор КАК Классификатор
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.КодСубъектаРФ = Классификатор.КодСубъектаРФ)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗагруженныеВерсииАдресныхСведений КАК ЗагруженныеВерсииАдресныхСведений
	|		ПО (Классификатор.КодСубъектаРФ = ЗагруженныеВерсииАдресныхСведений.КодСубъектаРФ)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СлужебныеАдресныеСведения КАК СлужебныеАдресныеСведения
	|		ПО (Классификатор.КодСубъектаРФ = (ВЫРАЗИТЬ(СлужебныеАдресныеСведения.Идентификатор КАК ЧИСЛО(2, 0))))
	|			И СлужебныеАдресныеСведения.Тип = &ТипСведений
	|ГДЕ
	|	АдресныеОбъекты.Уровень = 1
	|
	|УПОРЯДОЧИТЬ ПО
	|	КодСубъектаРФ";

	Запрос = Новый Запрос(ТекстЗапроса);

	Запрос.УстановитьПараметр("Классификатор", Классификатор);
	Запрос.УстановитьПараметр("ТипСведений",   "СубъектыРФ");
	Запрос.УстановитьПараметр("ТекущаяДата",   ТекущаяДатаСеанса());

	РезультатВыборкиЗагруженныхСведений = Запрос.Выполнить();
	Если РезультатВыборкиЗагруженныхСведений.Пустой() Тогда
		ВыполнитьНачальноеЗаполнение();
		РезультатВыборкиЗагруженныхСведений = Запрос.Выполнить();
		ЗагруженныеСведения = РезультатВыборкиЗагруженныхСведений.Выгрузить();

	Иначе

		ЗагруженныеСведения = РезультатВыборкиЗагруженныхСведений.Выгрузить();

		ТребуетсяВосстановлениеРегиона = Ложь;
		Для Каждого РегионИзКлассификатора Из Классификатор Цикл

			НайденныйРегион = ЗагруженныеСведения.Найти(РегионИзКлассификатора.Идентификатор, "Идентификатор");
			Если НайденныйРегион = Неопределено Тогда
				ТребуетсяВосстановлениеРегиона = Истина;
				Прервать;
			КонецЕсли;

		КонецЦикла;

		Если ТребуетсяВосстановлениеРегиона Тогда

			ВыполнитьНачальноеЗаполнение();
			РезультатВыборкиЗагруженныхСведений = Запрос.Выполнить();
			ЗагруженныеСведения = РезультатВыборкиЗагруженныхСведений.Выгрузить();

		КонецЕсли;

	КонецЕсли;

	ЗагруженныеСведения.Индексы.Добавить("Идентификатор");
	ЗагруженныеСведения.Индексы.Добавить("КодСубъектаРФ");
	ЗагруженныеСведения.Индексы.Добавить("Загружено");
	ЗагруженныеСведения.Индексы.Добавить("ОКТМО");
	
	Возврат ЗагруженныеСведения;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

Функция НавигационнаяСсылкаЗагрузкиАдресногоКлассификатора() Экспорт
	Возврат "e1cib/command/РегистрСведений.АдресныеОбъекты.Команда.ЗагрузитьАдресныйКлассификатор";
КонецФункции

// Параметры:
//   НазначениеРолей - см. ПользователиПереопределяемый.ПриОпределенииНазначенияРолей.НазначениеРолей
// 
Процедура ПриОпределенииНазначенияРолей(НазначениеРолей) Экспорт
	
	// ТолькоДляПользователейСистемы.
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ДобавлениеИзменениеАдресныхСведений.Имя);

КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента.
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт

	Параметры.Вставить("АдресныйКлассификаторУстарел", УстаревшийКлассификаторСодержитСведения());

КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт

	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	// Разрешение на проверку обновления.
	АдресФайлаВерсий = ОбщегоНазначенияКлиентСервер.СтруктураURI(
		АдресФайлаОписанияДоступныхВерсий());

	Протокол = ВРег(АдресФайлаВерсий.Схема);
	Адрес    = АдресФайлаВерсий.Хост;
	Порт     = АдресФайлаВерсий.Порт;
	Описание = НСтр("ru = 'Загрузка обновлений адресного классификатора.'");

	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");

	Разрешения = Новый Массив;
	Разрешения.Добавить( 
		МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеИнтернетРесурса(Протокол, Адрес, Порт, Описание));

	ВладелецРазрешения = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.РегистрыСведений.АдресныеОбъекты.ПолноеИмя());

	ЗапросРазрешений = МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения,
		ВладелецРазрешения, Истина);

	ЗапросыРазрешений.Добавить(ЗапросРазрешений);
	
	//  Веб-сервис

	АдресВебСервиса = ОбщегоНазначенияКлиентСервер.СтруктураURI(АдресВебСервисаКонтактнойИнформации());
	Протокол = ВРег(АдресВебСервиса.Схема);
	Адрес    = АдресВебСервиса.Хост;
	Порт     = АдресВебСервиса.Порт;
	Описание = НСтр("ru = 'Веб-сервис адресного классификатора.'");

	Разрешения = Новый Массив;
	Разрешения.Добавить( 
		МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеИнтернетРесурса(Протокол, Адрес, Порт, Описание));

	ВладелецРазрешения = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.РегистрыСведений.АдресныеОбъекты.ПолноеИмя());

	ЗапросРазрешений = МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения,
		ВладелецРазрешения, Истина);

	ЗапросыРазрешений.Добавить(ЗапросРазрешений);

КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	// Заполнение начальных данных.
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.8.219";
	Обработчик.Процедура = "АдресныйКлассификаторСлужебный.ВыполнитьНачальноеЗаполнение";
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.ОбщиеДанные         = Истина;
	Обработчик.РежимВыполнения = "Оперативно";

КонецПроцедуры

// См. ТекущиеДелаПереопределяемый.ПриОпределенииОбработчиковТекущихДел
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт

	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат; // Модель сервиса.
	КонецЕсли;

	Если Не ПравоДоступа("Изменение", Метаданные.РегистрыСведений.АдресныеОбъекты) Тогда
		Возврат; // Нет прав.
	КонецЕсли;
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");

	Подсистема = Метаданные.Подсистемы.Найти("Администрирование");
	Если Подсистема = Неопределено Или Не ПравоДоступа("Просмотр", Подсистема)
		Или Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(Подсистема) Тогда
		Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта("РегистрСведений.АдресныеОбъекты");
	Иначе
		Разделы = Новый Массив;
		Разделы.Добавить(Подсистема);
	КонецЕсли;
	
	// 1. Необходимость актуализировать адресный классификатор - в старом классификаторе больше нет записей о регионах.
	УстаревшийКлассификатор = ЗагруженыРегионыУстаревшегоКлассификатора();
	Для Каждого Раздел Из Разделы Цикл
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор  = "АктуализацияАдресногоКлассификатора";
		Дело.ЕстьДела       = УстаревшийКлассификатор;
		Дело.Важное         = Истина;
		Дело.СкрыватьВНастройках = Истина;
		Дело.Владелец       = Раздел;
		Дело.Представление  = НСтр("ru = 'Адресный классификатор устарел'");
		Дело.Количество     = 0;
		Дело.Подсказка      = НСтр("ru = 'Автоподбор и проверка корректности адресов временно недоступны.'");
		Дело.ПараметрыФормы = Новый Структура;
		Дело.Форма          = "РегистрСведений.АдресныеОбъекты.Форма.АктуализацияУстаревшегоКлассификатора";
		Если Дело.ЕстьДела = Истина Тогда
			Возврат;
		КонецЕсли;
	КонецЦикла;
	
	// 2. Необходимость обновления адресного классификатора.
	ПоследнееОбновление = ОписаниеПоследнейЗагрузки();
	Подсказка           = ПоследнееОбновление.Представление;
	Подсказка = Подсказка + Символы.ПС + НСтр("ru = 'Необходимо проверить наличие обновлений.'");
	Для Каждого Раздел Из Разделы Цикл
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор  = "ОбновлениеАдресногоКлассификатора";
		Дело.ЕстьДела       = ПоследнееОбновление.НеобходимоОбновление;
		Дело.Важное         = ПоследнееОбновление.НеобходимоОбновление;
		Дело.Владелец       = Раздел;
		Дело.Представление  = НСтр("ru = 'Адресный классификатор устарел'");
		Дело.Количество     = 0;
		Дело.Подсказка      = Подсказка;
		Дело.ПараметрыФормы = Новый Структура("Режим", "ПроверкаОбновления");
		Дело.Форма          = "РегистрСведений.АдресныеОбъекты.Форма.ЗагрузкаАдресногоКлассификатора";
		Если Дело.ЕстьДела = Истина Тогда
			Возврат;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Функция ЕстьПравоДобавлениеИзменениеАдресныхСведений() Экспорт
	Возврат ПравоДоступа("Изменение", Метаданные.РегистрыСведений.АдресныеОбъекты);
КонецФункции

// Устанавливает настройку использования веб-сервиса.
// 
// Параметры:
//  Использовать - Булево - если Ложь, то используются только загруженные данные из приложения.
//                          Иначе используется одновременно веб-сервис адресов и загруженные данные.
//
Процедура УстановитьИспользованиеВебСервиса(Использовать) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Источник = ?(Использовать, "Авто", "Приложение");
	Константы.ИсточникДанныхАдресногоКлассификатора.Установить(Источник);
	
КонецПроцедуры

// Возвращает настройку использования веб-сервиса.
//
// Возвращаемое значение:
//     Булево - если Ложь, то для подбора и проверки адресов используются только загруженные данные.
//              Иначе одновременно используются веб-сервис и загруженные данные.
//
Функция ИспользоватьВебСервис() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Источник = Константы.ИсточникДанныхАдресногоКлассификатора.Получить();
	Возврат СтрСравнить(Источник, "Приложение") <> 0;

КонецФункции

// Сведения об адресном объекта.
// 
// Параметры:
//  ИдентификаторАдреса - УникальныйИдентификатор - идентификатор адреса ГАР
// 
// Возвращаемое значение:
//  Структура - сведения об адресном объекта:
//   * Идентификатор - УникальныйИдентификатор
//   * ЗагруженныеДанные - Булево
//   * Муниципальный - Булево 
//   * Адрес - Структура
// 
Функция СведенияОбАдресномОбъекта(ИдентификаторАдреса) Экспорт
	
	СведенияОбАдресе = Новый Структура;
	СведенияОбАдресе.Вставить("Идентификатор",     ИдентификаторАдреса);
	СведенияОбАдресе.Вставить("ЗагруженныеДанные", Ложь);
	СведенияОбАдресе.Вставить("Муниципальный",     Ложь);
	СведенияОбАдресе.Вставить("Адрес",             Новый Структура);
	
	Возврат СведенияОбАдресе;
	
КонецФункции

#Область АдресныйКлассификаторВМоделиСервиса

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ПоставляемыеДанныеПереопределяемый.ПолучитьОбработчикиПоставляемыхДанных.
Процедура ПриОпределенииОбработчиковПоставляемыхДанных(Обработчики) Экспорт

	ЗарегистрироватьОбработчикиПоставляемыхДанных(Обработчики);

КонецПроцедуры

// Параметры:
//   Типы - см. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки.Типы
// 
Процедура ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки(Типы) Экспорт

	Типы.Добавить(Метаданные.Константы.ИсточникДанныхАдресногоКлассификатора);

	МетаданныеРегистров = Метаданные.РегистрыСведений;
	
	Типы.Добавить(МетаданныеРегистров.АдресныеОбъекты);
	Типы.Добавить(МетаданныеРегистров.ДомаЗданияСтроения);
	Типы.Добавить(МетаданныеРегистров.ДополнительныеАдресныеСведения);
	Типы.Добавить(МетаданныеРегистров.ЗагруженныеВерсииАдресныхСведений);
	Типы.Добавить(МетаданныеРегистров.ИсторияАдресныхОбъектов);
	Типы.Добавить(МетаданныеРегистров.ПричиныИзмененияАдресныхСведений);
	Типы.Добавить(МетаданныеРегистров.СлужебныеАдресныеСведения);
	Типы.Добавить(МетаданныеРегистров.УровниСокращенийАдресныхСведений);

КонецПроцедуры

// Вызывается при получении уведомления о новых данных.
// В теле следует проверить, необходимы ли эти данные приложению, 
// и если да - установить флажок Загружать.
// 
// Параметры:
//   Дескриптор - ОбъектXDTO - дескриптор.
//   Загружать - Булево - Истина, если загружать, Ложь - иначе.
//
Процедура ДоступныНовыеДанные(Знач Дескриптор, Загружать) Экспорт

	Если Дескриптор.DataType = "ГАР" Тогда

		Загружать = ПроверитьНаличиеНовыхДанных(Дескриптор);

	КонецЕсли;

КонецПроцедуры

// Вызывается после вызова ДоступныНовыеДанные, позволяет разобрать данные.
//
// Параметры:
//   Дескриптор - ОбъектXDTO - дескриптор.
//   ПутьКФайлу - Строка - полное имя извлеченного файла. Файл будет автоматически удален 
//                  после завершения процедуры. Если в менеджере сервиса не был
//                  указан файл - значение аргумента равно Неопределено.
//
Процедура ОбработатьНовыеДанные(Знач Дескриптор, Знач ПутьКФайлу) Экспорт

	Если Дескриптор.DataType = "ГАР" Тогда
		ОбработатьАдресныйКлассификатор(Дескриптор, ПутьКФайлу);
	КонецЕсли;

КонецПроцедуры

// Вызывается при отмене обработки данных в случае сбоя.
// 
// Параметры:
//  Дескриптор - ОбъектXDTO - дескриптор
//
Процедура ОбработкаДанныхОтменена(Знач Дескриптор) Экспорт

КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция АдаптацияНазванияРегиона(Название) Экспорт
	
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Если СтрСравнить(Название, "Кемеровская область - Кузбасс обл") = 0
	 Или СтрСравнить(Название, "Кемеровская область - Кузбасс область") = 0
	 Или СтрСравнить(Название, "Кемеровская область") = 0
	 Или СтрСравнить(Название, ИсторическоеНаименованиеКемеровскойОбласти()) = 0  Тогда
		Возврат ДействующиеНаименованиеКемеровскойОбласти();
	КонецЕсли;
	// АПК: 1297-вкл

	Название = СокрЛП(Название);
	Если СтрЗаканчиваетсяНа(Название, ".") Тогда
		Название = Лев(Название, СтрДлина(Название) - 1);
	КонецЕсли;

	Возврат Название;

КонецФункции

Функция ДействующиеНаименованиеКемеровскойОбласти() Экспорт
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Возврат "Кемеровская область - Кузбасс";
	// АПК: 1297-вкл
КонецФункции

Функция ИсторическоеНаименованиеКемеровскойОбласти()
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Возврат "Кемеровская обл";
	// АПК: 1297-вкл
КонецФункции

Процедура ОбновитьСписокУровней(Адрес, ИмяУровня, ЕстьЗначение)
	
	Если ИмяУровня <> "district" Тогда
		ПозицияМуниципальныйУровень = Адрес.munLevels.Найти(ИмяУровня);
	Иначе
		ПозицияМуниципальныйУровень = -1;
	КонецЕсли;
	
	Если ИмяУровня <> "munDistrict" И ИмяУровня <> "settlement" Тогда
		ПозицияАдминистративнойУровень = Адрес.admLevels.Найти(ИмяУровня);
	Иначе
		ПозицияАдминистративнойУровень = -1;
	КонецЕсли;
	
	Если ЕстьЗначение Тогда
		Если ПозицияМуниципальныйУровень = Неопределено Тогда
			Адрес.munLevels.Добавить(ИмяУровня);
		КонецЕсли;
		Если ПозицияАдминистративнойУровень = Неопределено Тогда
			Адрес.admLevels.Добавить(ИмяУровня);
		КонецЕсли;
	Иначе
		Если ПозицияМуниципальныйУровень <> Неопределено И ПозицияМуниципальныйУровень >= 0 Тогда
			Адрес.munLevels.Удалить(ПозицияМуниципальныйУровень);
		КонецЕсли;
		Если ПозицияАдминистративнойУровень <> Неопределено И ПозицияАдминистративнойУровень >= 0 Тогда
			Адрес.admLevels.Удалить(ПозицияАдминистративнойУровень);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   НаименованияАдресныхОбъектов - Массив
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Наименование - Строка
//    * Сокращение - Строка
// 
Функция ТаблицаАдресныхСокращений(НаименованияАдресныхОбъектов)

	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	УровниСокращенийАдресныхСведений.Значение КАК Наименование,
	|	УровниСокращенийАдресныхСведений.Сокращение КАК Сокращение
	|ИЗ
	|	РегистрСведений.УровниСокращенийАдресныхСведений КАК УровниСокращенийАдресныхСведений 
	|ГДЕ
	|	&Условие
	|
	|СГРУППИРОВАТЬ ПО
	|	УровниСокращенийАдресныхСведений.Значение,
	|	УровниСокращенийАдресныхСведений.Сокращение
	|
	|УПОРЯДОЧИТЬ ПО
	|	Наименование";
	
	Если ТипЗнч(НаименованияАдресныхОбъектов) = Тип("Массив") И НаименованияАдресныхОбъектов.Количество() > 0 Тогда
		Условие = "ИСТИНА";
	Иначе
		Условие = "УровниСокращенийАдресныхСведений.Значение В(&АдресныеСокращения)";
		Запрос.УстановитьПараметр("АдресныеСокращения", НаименованияАдресныхОбъектов);
	КонецЕсли;
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&Условие", Условие);

	Возврат Запрос.Выполнить().Выгрузить();

КонецФункции

Функция ИдентификаторАдресногоОбъекта(Адрес)

	Идентификатор = "";
	ИменаУровнейАдреса = ИменаУровнейАдреса(Адрес, Истина, Истина);
	Для Каждого УровеньАдреса Из ИменаУровнейАдреса Цикл
		Если ЗначениеЗаполнено(Адрес[УровеньАдреса + "Id"]) Тогда
			Идентификатор = Адрес[УровеньАдреса + "Id"];
		КонецЕсли;
	КонецЦикла;

	Возврат Идентификатор;

КонецФункции

// Возвращает настройку текущего источника данных адресов.
//
// Возвращаемое значение:
//     Строка - описание источника. Пустая строка - используются загружаемые в регистр данные.
//
Функция ИсточникДанныхАдресногоКлассификатора()
	
	Возврат ПолучитьФункциональнуюОпцию("ИсточникДанныхАдресногоКлассификатора");

КонецФункции

Функция РаспознатьАдресВебСервис(ЧастиАдреса, Знач Представление, ВСтруктуру)

	Адрес = ОписаниеНовойКонтактнойИнформации();
	АдресДляПроверки = Новый Массив;
	Помещения = Новый Массив;

	ТипыЗданий = СписокТиповЗданий();
	Для Каждого ЧастьАдреса Из ЧастиАдреса Цикл

		Если ЧастьАдреса.Уровень < 0 Тогда
			Продолжить;
		КонецЕсли;

		Если СтрСравнить(СтрСоединить(СтрРазделить(ЧастьАдреса.ТипОбъекта, "0123456789")), ЧастьАдреса.ТипОбъекта) <> 0 Тогда
			Если ТипыЗданий.Получить(ВРег(ЧастьАдреса.Наименование)) = Неопределено Тогда
				Помещения.Добавить(ЗначениеСтроенияИлиПомещения(ТРег(ЧастьАдреса.Наименование), ЧастьАдреса.ТипОбъекта));
				Продолжить;
			КонецЕсли;
		КонецЕсли;

		АдресДляПроверки.Добавить(ЧастьАдреса.Значение);

	КонецЦикла;

	Представление = СтрЗаменить(Представление, "№", ""); // Обратная совместимость
	Представление = СтрЗаменить(Представление, "  ", " ");

	ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("recognize?text=%1&limit=20",
		КодироватьСтроку(Представление, СпособКодированияСтроки.КодировкаURL));

	РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);
	Если РезультатВебСервис.Отказ Или РезультатВебСервис.Количество() = 0 Или РезультатВебСервис.Данные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	Если РезультатВебСервис.Данные.status = "COMPLETELY_RECOGNIZED" Тогда
		Адрес = АдресДляСохраненияВБазе(РезультатВебСервис.Данные.value, Ложь);
	Иначе
		Если РезультатВебСервис.Данные.status = "PARTIALLY_RECOGNIZED" И ВСтруктуру Тогда
			Адрес = АдресДляСохраненияВБазе(РезультатВебСервис.Данные.value, Ложь);
			Адрес.comment = НСтр("ru = 'Нераспознанная часть адреса'") + ": "
				+ РезультатВебСервис.Данные.unrecognizedPart;
		Иначе
			Адрес = ОписаниеНовойКонтактнойИнформации();
			Адрес.street  = Представление;
			Адрес.value   = Представление;
			Адрес.country = ОсновнаяСтрана();
		КонецЕсли;
		Возврат Адрес;
	КонецЕсли;

	Если СтрСравнить(РезультатВебСервис.Данные.addressType, "MUNICIPAL") = 0 Тогда
		Адрес.addressType = МуниципальныйАдрес();
	Иначе
		Адрес.addressType = АдминистративноТерриториальныйАдрес();
	КонецЕсли;

	Возврат Адрес;

КонецФункции

Функция СписокТиповЗданий()

	ТипыЗданий = Новый Соответствие;
	Для Каждого ТипОбъектовАдресации Из ТипыОбъектовАдресацииАдресаРФ() Цикл

		Если ТипОбъектовАдресации.Тип = 1 Или ТипОбъектовАдресации.Тип = 2 Тогда
			ТипыЗданий.Вставить(ВРег(ТипОбъектовАдресации.Наименование), ТипОбъектовАдресации.Код);
		КонецЕсли;

	КонецЦикла;

	Возврат ТипыЗданий;

КонецФункции

Функция ОпределитьКодРегионаПоЧастямАдреса(Знач ЧастиАдреса)
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ДанныеАдреса.Уровень КАК Уровень,
	|	ДанныеАдреса.Позиция КАК Позиция,
	|	ДанныеАдреса.Значение КАК Значение,
	|	ДанныеАдреса.Наименование КАК Наименование,
	|	ДанныеАдреса.ТипОбъекта КАК ТипОбъекта
	|ПОМЕСТИТЬ ДанныеАдреса
	|ИЗ
	|	&ДанныеАдреса КАК ДанныеАдреса
	|ГДЕ
	|	ДанныеАдреса.Уровень >= 0
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	Уровень,
	|	Позиция,
	|	Наименование,
	|	ТипОбъекта
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ
	|ИЗ
	|	ДанныеАдреса КАК ДанныеАдреса
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО ДанныеАдреса.Наименование = АдресныеОбъекты.Наименование
	|			И ДанныеАдреса.ТипОбъекта = АдресныеОбъекты.ТипОбъекта
	|ГДЕ
	|	АдресныеОбъекты.Уровень = 1";

	Запрос.УстановитьПараметр("ДанныеАдреса", ЧастиАдреса);
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();

	Если РезультатЗапроса.Количество() > 0 Тогда
		КодРегиона = РезультатЗапроса[0].КодСубъектаРФ;
	Иначе
		Для Каждого ЧастьАдреса Из ЧастиАдреса Цикл
			
			КодРегиона = АдресныйКлассификатор.КодРегионаПоНаименованию(ЧастьАдреса.Значение);
			Если КодРегиона <> Неопределено Тогда
				Прервать;
			КонецЕсли;
			
		КонецЦикла;
		
		Если КодРегиона <> Неопределено Тогда
			Запрос = Новый Запрос;
			Запрос.Текст =
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	АдресныеОбъекты.Наименование КАК Наименование,
			|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта
			|ИЗ
			|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
			|ГДЕ
			|	АдресныеОбъекты.Уровень = 1
			|	И АдресныеОбъекты.КодСубъектаРФ = &КодСубъектаРФ";
				
				Запрос.УстановитьПараметр("КодСубъектаРФ", КодРегиона);
				
				РезультатЗапроса = Запрос.Выполнить().Выгрузить();
				
				Если РезультатЗапроса.Количество() > 0 Тогда
					ЗаполнитьЗначенияСвойств(ЧастьАдреса, РезультатЗапроса[0]);
				КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат КодРегиона;

КонецФункции

Функция РаспознатьАдресЗагруженныеДанные(ЧастиАдреса, КодРегиона)

	ОбработатьОбщепринятыеСокращения(ЧастиАдреса);
	Адрес = ОписаниеНовойКонтактнойИнформации();

	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ДанныеАдреса.Уровень КАК Уровень,
	|	ДанныеАдреса.Позиция КАК Позиция,
	|	ДанныеАдреса.Значение КАК Значение,
	|	ДанныеАдреса.Наименование КАК Наименование,
	|	ДанныеАдреса.ТипОбъекта КАК ТипОбъекта
	|ПОМЕСТИТЬ ДанныеАдреса
	|ИЗ
	|	&ДанныеАдреса КАК ДанныеАдреса
	|ГДЕ ДанныеАдреса.Уровень >= 0
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	Уровень,
	|	Позиция,
	|	Наименование,
	|	ТипОбъекта
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 10
	|	МАКСИМУМ(АдресныеОбъекты.Уровень) КАК Уровень,
	|	ДанныеАдреса.Позиция КАК Позиция,
	|	ДанныеАдреса.Наименование КАК Наименование,
	|	ДанныеАдреса.ТипОбъекта КАК ТипОбъекта
	|ИЗ
	|	ДанныеАдреса КАК ДанныеАдреса
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (ДанныеАдреса.Наименование = АдресныеОбъекты.Наименование)
	|			И (ДанныеАдреса.ТипОбъекта = АдресныеОбъекты.ТипОбъекта)
	|ГДЕ
	|	НЕ АдресныеОбъекты.Идентификатор ЕСТЬ NULL
	|
	|СГРУППИРОВАТЬ ПО
	|	ДанныеАдреса.Наименование,
	|	ДанныеАдреса.ТипОбъекта,
	|	ДанныеАдреса.Позиция
	|
	|УПОРЯДОЧИТЬ ПО ДанныеАдреса.Позиция
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ДанныеАдреса.Позиция КАК Позиция,
	|	ДанныеАдреса.Значение КАК Значение,
	|	ДанныеАдреса.Наименование КАК Наименование,
	|	ДанныеАдреса.ТипОбъекта КАК ТипОбъекта
	|
	|ИЗ
	|	ДанныеАдреса КАК ДанныеАдреса
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО ДанныеАдреса.Наименование = АдресныеОбъекты.Наименование
	|			И ДанныеАдреса.ТипОбъекта = АдресныеОбъекты.ТипОбъекта
	|ГДЕ
	|	АдресныеОбъекты.Идентификатор ЕСТЬ NULL
	|
	|УПОРЯДОЧИТЬ ПО ДанныеАдреса.Позиция
	|";

	Запрос.УстановитьПараметр("ДанныеАдреса", ЧастиАдреса);
	РезультатЗапроса = Запрос.ВыполнитьПакет();

	СопоставленныеЧастиАдреса = СопоставленныеЧастиАдреса(РезультатЗапроса);

	Если СопоставленныеЧастиАдреса.Количество() = 0 Тогда
		Возврат Адрес;
	КонецЕсли;
	
	// дома 
	ДомаЗдания = ДомаЗдания(РезультатЗапроса);
	
	КодыДомовВладенийИСтроений = КодыДомовВладенийИСтроений();
	СокращенияНаименованийДомов = АдресныйКлассификаторПовтИсп.СокращенияНаименованийДомов();
	СокращенияНаименованийПомещений = АдресныйКлассификаторПовтИсп.СокращенияНаименованийПомещений();

	Квартиры = Новый Массив;
	Строения = Новый Массив;

	СведенияОДоме = СведенияОДоме();
	СведенияОЗемельномУчастке = "";

	Для Каждого ЭлементАдреса Из ДомаЗдания Цикл

		ТипОбъекта = ВРег(СокрЛП(СтрЗаменить(ЭлементАдреса.ТипОбъекта, "№", "")));
		Значение = ЭлементАдреса.Наименование;
		
		Если СтрСравнить(ТипОбъекта, "З/У") = 0 Тогда
			СведенияОЗемельномУчастке = Значение;
			Продолжить
		КонецЕсли;
		
		ТипДомаИлиСтроения = "";
		Если КодыДомовВладенийИСтроений.Дома[ТипОбъекта] <> Неопределено Тогда
			ТипДомаИлиСтроения = ТРег(ЭлементАдреса.ТипОбъекта);
		ИначеЕсли СокращенияНаименованийДомов.Получить(ВРег(ТипОбъекта)) <> Неопределено Тогда
			ТипДомаИлиСтроения = СокращенияНаименованийДомов.Получить(ВРег(ТипОбъекта));
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ТипДомаИлиСтроения) Тогда
			Если ПустаяСтрока(СведенияОДоме.НаименованиеДома) Тогда
				СведенияОДоме.НаименованиеДома = ТипДомаИлиСтроения;
				СведенияОДоме.НомерДома        = Значение;
			ИначеЕсли ПустаяСтрока(СведенияОДоме.НаименованиеДополнительногоДома1) Тогда
				СведенияОДоме.НаименованиеДополнительногоДома1 = ТипДомаИлиСтроения;
				СведенияОДоме.ДополнительныйНомерДома1         = Значение;
				Строения.Добавить(ЗначениеСтроенияИлиПомещения(ТипДомаИлиСтроения, Значение));
			ИначеЕсли ПустаяСтрока(СведенияОДоме.НаименованиеДополнительногоДома2) Тогда
				СведенияОДоме.НаименованиеДополнительногоДома2 = ТипДомаИлиСтроения;
				СведенияОДоме.ДополнительныйНомерДома2         = Значение;
				Строения.Добавить(ЗначениеСтроенияИлиПомещения(ТипДомаИлиСтроения, Значение));
			Иначе
				Строения.Добавить(ЗначениеСтроенияИлиПомещения(ТипДомаИлиСтроения, Значение));
			КонецЕсли;
		Иначе
			
			ТипПомещения = ТРег(ЭлементАдреса.ТипОбъекта);
			Если СокращенияНаименованийПомещений.Получить(ВРег(ТипПомещения)) <> Неопределено Тогда
				ТипПомещения = СокращенияНаименованийПомещений.Получить(ВРег(ТипПомещения));
			КонецЕсли;
			
			Квартиры.Добавить(ЗначениеСтроенияИлиПомещения(ТипПомещения, Значение));
		КонецЕсли;

	КонецЦикла;

	АдресаПоПолям = НоваяТаблицаАдресовСРазбивкойНаПоля();

	АдресМуниципальный = АдресаПоПолям.Добавить();
	АдресМуниципальный.Ключ = 0;
	АдресМуниципальный.ЭтоМуниципальныйАдрес = Истина;

	АдресАдминистративный = АдресаПоПолям.Добавить();
	АдресАдминистративный.Ключ = 1;
	АдресАдминистративный.ЭтоМуниципальныйАдрес = Ложь;
	
	Для Позиция = 0 По СопоставленныеЧастиАдреса.Количество() - 1 Цикл
		АдресМуниципальный["Наименование" + Строка(Позиция)]    = СопоставленныеЧастиАдреса[Позиция]["Наименование"];
		АдресМуниципальный["ТипОбъекта" + Строка(Позиция)]      = СопоставленныеЧастиАдреса[Позиция]["ТипОбъекта"];
		АдресАдминистративный["Наименование" + Строка(Позиция)] = СопоставленныеЧастиАдреса[Позиция]["Наименование"];
		АдресАдминистративный["ТипОбъекта" + Строка(Позиция)]   = СопоставленныеЧастиАдреса[Позиция]["ТипОбъекта"];
	КонецЦикла;
	
	КодыРегионов = Новый Массив;
	КодыРегионов.Добавить(КодРегиона);
	
	Запрос.Текст = ТекстЗапросаПроверкиАдресов();
	Запрос.УстановитьПараметр("АдресаПоПолям", АдресаПоПолям);
	Запрос.УстановитьПараметр("КодыРегионов",  КодыРегионов);
	
	РезультатЗапроса       = Запрос.ВыполнитьПакет();
	ВариантыАдресов        = РезультатЗапроса[13];
	ДомаИСведения          = РезультатЗапроса[14];
	Участки                = РезультатЗапроса[15];

	Если ВариантыАдресов.Пустой() Тогда
		Возврат Адрес; // Не удалось распознать адрес.
	КонецЕсли;
	НайденныеАдреса= ВариантыАдресов.Выгрузить();

	Если НайденныеАдреса.Количество() > 1 И НайденныеАдреса[0].Уровень < НайденныеАдреса[1].Уровень Тогда
		СтрокаАдреса = НайденныеАдреса[1];
	Иначе
		СтрокаАдреса = НайденныеАдреса[0];
	КонецЕсли;

	СтрокаИндекс = ЧастиАдреса.Найти(-1, "Уровень");
	ПочтовыйИндекс = ?(СтрокаИндекс <> Неопределено, СтрокаИндекс.Значение, "");

	Муниципальный = ?(СтрокаАдреса.КлючАдреса = 0, Истина, Ложь);

	Сведения = СведенияОбАдресномОбъекта(СтрокаАдреса.Идентификатор);
	Сведения.ЗагруженныеДанные = Истина;
	Сведения.Муниципальный     = Муниципальный;

	АдресДанные = АктуальныеАдресныеСведения(Сведения);

	Адрес = СформироватьАдресПоДаннымИзКлассификатора(АдресДанные.Данные);
	Адрес.AddressType = ?(Муниципальный, МуниципальныйАдрес(), АдминистративноТерриториальныйАдрес());

	Адрес.HouseType   = ТРег(СведенияОДоме.НаименованиеДома);
	Адрес.HouseNumber = ТРег(СведенияОДоме.НомерДома);
	
	Если ЗначениеЗаполнено(СведенияОЗемельномУчастке) Тогда
		
		ДанныеОбУчастке = НайтиСтрокуСЗемельнымУчастком(Участки.Выгрузить(), СведенияОЗемельномУчастке);
		Адрес.stead   = ДанныеОбУчастке.НомерЗемельногоУчастка;
		Адрес.steadId = ДанныеОбУчастке.ИдентификаторУчастка;
		
	КонецЕсли;

	Адрес.Buildings   = Строения;
	Адрес.Apartments  = Квартиры;

	ОписаниеДома = НайтиСтрокуСДомом(ДомаИСведения.Выгрузить(), СведенияОДоме);
	Если ОписаниеДома <> Неопределено Тогда
		Адрес.HouseID     = ОписаниеДома.ИдентификаторДома;
		Адрес.OKTMO = Формат(ОписаниеДома.ОКТМО, "ЧГ=0");
		Адрес.OKATO = Формат(ОписаниеДома.ОКАТО, "ЧГ=0");

		Адрес.IFNSFLCode = ОписаниеДома.КодИФНСФЛ;
		Адрес.IFNSULCode = ОписаниеДома.КодИФНСЮЛ;
		Адрес.IFNSFLAreaCode = ОписаниеДома.КодУчасткаИФНСФЛ;
		Адрес.IFNSULAreaCode = ОписаниеДома.КодУчасткаИФНСЮЛ;
		Если ПустаяСтрока(ПочтовыйИндекс) Тогда
			ПочтовыйИндекс = Формат(ОписаниеДома.Индекс, "ЧГ=0");
		КонецЕсли;
	КонецЕсли;

	Адрес.ZIPcode = ПочтовыйИндекс;

	Возврат Адрес;

КонецФункции

// Параметры:
//  РезультатЗапроса - Массив
//  
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Позиция - Число
//    * Значение - Строка
//    * Наименование - Строка
//    * ТипОбъекта - Строка
//
Функция ДомаЗдания(Знач РезультатЗапроса)

	ДомаЗдания                = РезультатЗапроса[2].Выгрузить();
	Возврат ДомаЗдания

КонецФункции

// Параметры:
//  РезультатЗапроса - Массив
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//     * Уровень - Число
//     * Позиция - Число
//     * Наименование - Строка
//     * ТипОбъекта - Строка
// 
Функция СопоставленныеЧастиАдреса(Знач РезультатЗапроса)

	СопоставленныеЧастиАдреса = РезультатЗапроса[1].Выгрузить();
	Возврат СопоставленныеЧастиАдреса

КонецФункции

Функция АдминистративноТерриториальныйАдрес()
	Возврат "Административно-территориальный";
КонецФункции

Функция МуниципальныйАдрес()
	Возврат "Муниципальный";
КонецФункции

Функция СоединитьНаименованиеИТипАдресногоОбъекта(Знач Наименование, Знач ТипАдресногоОбъекта, ЭтоРегион = Ложь) Экспорт

	Если ПустаяСтрока(ТипАдресногоОбъекта) Тогда
		Возврат Наименование;
	КонецЕсли;

	Если ЭтоРегион Тогда
		
		Если НаименованиеРегионаБезТипа(Наименование) Тогда
			Возврат Наименование;
		КонецЕсли;
		
		Возврат Наименование + " " + ТипАдресногоОбъекта;
	КонецЕсли;

	Возврат ТипАдресногоОбъекта + " " + Наименование;

КонецФункции

Процедура УстановитьИдентификаторыАдресаЧерезВебСервис(АдресаДляПроверки)

	Результат = ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(АдресаДляПроверки);

	Если Результат.Отказ = Ложь Тогда

			Если Результат.Данные.Количество() > 0 Тогда

			Для Каждого АдресДляПроверки Из АдресаДляПроверки Цикл

				АдресИзСервиса = Результат.Данные[АдресДляПроверки.Ключ]; // см. РезультатПроверкиАдреса
				Если АдресИзСервиса.Варианты.Количество() > 0 Тогда
					ВариантИзСервиса = АдресИзСервиса.Варианты[0];

					Адрес = АдресДляПроверки.Значение;
					Для Каждого КлючЗначение Из Адрес Цикл

						Если СтрЗаканчиваетсяНа(ВРег(КлючЗначение.Ключ), "ID") Тогда
							Адрес[КлючЗначение.Ключ] = ?(ВариантИзСервиса.Свойство(КлючЗначение.Ключ),
								ВариантИзСервиса[КлючЗначение.Ключ], "");
						КонецЕсли;

					КонецЦикла;
				КонецЕсли;
			КонецЦикла;

		КонецЕсли;

	КонецЕсли;

КонецПроцедуры

Процедура УстановитьИдентификаторыАдресовПоЗагруженнымДанным(Адреса)

	ПодготовленныеДанные = ПервичнаяПроверкаАдресов(Адреса);
	Результаты   = ПодготовленныеДанные.Адреса;
	КодыРегионов = ПодготовленныеДанные.КодыРегионов;

	Запрос = Новый Запрос;

	ДанныеДляПроверкиАдресов = СформироватьДанныеДляПроверкиАдресов(Адреса, Результаты);
	Запрос.УстановитьПараметр("АдресаПоПолям", ДанныеДляПроверкиАдресов.АдресаПоПолям);
	Запрос.УстановитьПараметр("КодыРегионов", КодыРегионов);

	Запрос.Текст = ТекстЗапросаПроверкиАдресов();

	РезультатЗапроса        = Запрос.ВыполнитьПакет();
	РезультатЗапросаАдреса  = РезультатЗапроса[13];
	РезультатЗапросаДома    = РезультатЗапроса[14];

	Если РезультатЗапросаАдреса.Пустой() Тогда
		Возврат;
	КонецЕсли;

	ПолученныйАдрес = РезультатЗапросаАдреса.Выбрать();
	Пока ПолученныйАдрес.Следующий() Цикл

		Адрес = Адреса[ПолученныйАдрес.КлючАдреса];
		КакиеУровниПроверять = ДанныеДляПроверкиАдресов.ПроверяемыеУровни[ПолученныйАдрес.КлючАдреса];

		ИдентификаторАдресногоОбъекта = Неопределено;
		МаксимальныйУровень = -1;
		Для Каждого Уровни Из КакиеУровниПроверять Цикл
			НайденныйИдентификатор = ПолученныйАдрес["ИдентификаторУровень" + Уровни.Значение];
			Если ЗначениеЗаполнено(НайденныйИдентификатор) Тогда
				Адрес[Уровни.Ключ + "Id"] = НайденныйИдентификатор;
				Если МаксимальныйУровень < Уровни.Значение Тогда
					ИдентификаторАдресногоОбъекта = НайденныйИдентификатор;
					МаксимальныйУровень           = Уровни.Значение;
				КонецЕсли;
			Иначе
				Адрес[Уровни.Ключ + "Id"] = "";
			КонецЕсли;

		КонецЦикла;
		Адрес["id"] = ИдентификаторАдресногоОбъекта;

		Если Не ЗначениеЗаполнено(ИдентификаторАдресногоОбъекта) Тогда
			Продолжить;
		КонецЕсли;

		Если РезультатЗапросаДома.Пустой() Тогда
			Продолжить;
		КонецЕсли;

		СведенияОДоме = СведенияОДоме();
		ИзвлечьСтроенияВОписаниеДома(СведенияОДоме, Адрес);

		Результат = НайтиСтрокуСДомом(РезультатЗапросаДома.Выгрузить(), СведенияОДоме);
		Если Результат <> Неопределено Тогда
			Адрес.HouseID = Результат.ИдентификаторДома;
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

// Начальное заполнение данных адресного классификатора при первом запуске.
//
Процедура ВыполнитьНачальноеЗаполнение() Экспорт

	РегистрыСведений.АдресныеОбъекты.ОбновитьСоставСубъектовРФПоКлассификатору(Истина);

КонецПроцедуры

// Конструктор таблицы - результата выбора по почтовому индексу.
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Муниципальный - Булево
//    * ЗагруженныеДанные - Булево
//    * Идентификатор - УникальныйИдентификатор
//    * Представление - Строка
//
Функция ТаблицаДанныхДляВыбораПоПочтовомуИндексу()

	Данные = Новый ТаблицаЗначений;
	Данные.Колонки.Добавить("Муниципальный",     Новый ОписаниеТипов("Булево"));
	Данные.Колонки.Добавить("ЗагруженныеДанные", Новый ОписаниеТипов("Булево"));
	Данные.Колонки.Добавить("Идентификатор",     Новый ОписаниеТипов("УникальныйИдентификатор"));
	Данные.Колонки.Добавить("Представление",     Новый ОписаниеТипов("Строка"));

	Данные.Индексы.Добавить("Представление");

	Возврат Данные;
	
КонецФункции

Функция ОпределитьИдентификаторыАдреса(АдресДляПроверки) Экспорт

	Результат = НовыйРезультатОпределенияИдентификатораАдреса();

	Попытка
		ОпределитьИдентификаторыАдресаСервис1С(Результат, АдресДляПроверки);
	Исключение
		СтруктураОписанияОшибкиПоставщика(Результат, ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
			Результат.ПодробноеПредставлениеОшибки);
	КонецПопытки;

	Возврат Результат;

КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Отказ - Булево
//   * ИдентификаторАдресногоОбъекта - УникальныйИдентификатор, Неопределено
//   * ИдентификаторДома - УникальныйИдентификатор, Неопределено
//   * ПодробноеПредставлениеОшибки - Строка
//   *   КраткоеПредставлениеОшибки - Строка
//
Функция НовыйРезультатОпределенияИдентификатораАдреса()
	
	Результат = Новый Структура;
	
	Результат.Вставить("Отказ", Ложь);
	Результат.Вставить("ИдентификаторАдресногоОбъекта", Неопределено);
	Результат.Вставить("ИдентификаторДома", Неопределено);
	Результат.Вставить("ПодробноеПредставлениеОшибки", "");
	Результат.Вставить("КраткоеПредставлениеОшибки", "");
	
	Возврат Результат;
	
КонецФункции

// Заполнение актуальных данных адресного объекта или ориентира из загруженных данных.
//
Процедура ЗаполнитьАдресныеСведенияИзЗагруженныхДанных(Результат, СведенияОбАдресномОбъекте)

	Если Не ЗначениеЗаполнено(СведенияОбАдресномОбъекте.Идентификатор) Тогда
		Возврат;
	КонецЕсли;

	Запрос = Новый Запрос;

	ТекстЗапроса = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	&ПредставлениеМуниципальный КАК ТипАдреса,
	|	АдресныеОбъекты5.Наименование КАК Наименование5,
	|	АдресныеОбъекты5.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныеОбъекты5.Идентификатор КАК Идентификатор5,
	|	АдресныеОбъекты5.Уровень КАК Уровень5,
	|	АдресныеОбъекты4.Наименование КАК Наименование4,
	|	АдресныеОбъекты4.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныеОбъекты4.Идентификатор КАК Идентификатор4,
	|	АдресныеОбъекты4.Уровень КАК Уровень4,
	|	АдресныеОбъекты3.Наименование КАК Наименование3,
	|	АдресныеОбъекты3.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныеОбъекты3.Идентификатор КАК Идентификатор3,
	|	АдресныеОбъекты3.Уровень КАК Уровень3,
	|	АдресныеОбъекты2.Наименование КАК Наименование2,
	|	АдресныеОбъекты2.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныеОбъекты2.Идентификатор КАК Идентификатор2,
	|	АдресныеОбъекты2.Уровень КАК Уровень2,
	|	АдресныеОбъекты1.Наименование КАК Наименование1,
	|	АдресныеОбъекты1.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныеОбъекты1.Идентификатор КАК Идентификатор1,
	|	АдресныеОбъекты1.Уровень КАК Уровень1,
	|	АдресныеОбъекты0.Наименование КАК Наименование0,
	|	АдресныеОбъекты0.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныеОбъекты0.Идентификатор КАК Идентификатор0,
	|	АдресныеОбъекты0.Уровень КАК Уровень0,
	|	АдресныеОбъекты0.КодКЛАДР КАК КодКЛАДР,
	|	АдресныеОбъекты0.КодСубъектаРФ КАК КодСубъектаРФ,
	|	ЕСТЬNULL(ДополнительныеСведения.ПочтовыйИндекс, """") КАК ПочтовыйИндекс,
	|	ЕСТЬNULL(ДополнительныеСведения.ОКТМО, """") КАК ОКТМО,
	|	ЕСТЬNULL(ДополнительныеСведения.OKATO, """") КАК OKATO,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСЮЛ, """") КАК КодУчасткаИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСФЛ, """") КАК КодУчасткаИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСЮЛ, """") КАК КодИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСФЛ, """") КАК КодИФНСФЛ
	|ИЗ
	|	РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия0
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия1
	|		ПО (МуниципальнаяИерархия0.РодительскийИдентификатор = МуниципальнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия2
	|		ПО (МуниципальнаяИерархия1.РодительскийИдентификатор = МуниципальнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия3
	|		ПО (МуниципальнаяИерархия2.РодительскийИдентификатор = МуниципальнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия4
	|		ПО (МуниципальнаяИерархия3.РодительскийИдентификатор = МуниципальнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия5
	|		ПО (МуниципальнаяИерархия4.РодительскийИдентификатор = МуниципальнаяИерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты0
	|		ПО (АдресныеОбъекты0.Идентификатор = МуниципальнаяИерархия0.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты1
	|		ПО (АдресныеОбъекты1.Идентификатор = МуниципальнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты2
	|		ПО (АдресныеОбъекты2.Идентификатор = МуниципальнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты3
	|		ПО (АдресныеОбъекты3.Идентификатор = МуниципальнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты4
	|		ПО (АдресныеОбъекты4.Идентификатор = МуниципальнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты5
	|		ПО (АдресныеОбъекты5.Идентификатор = МуниципальнаяИерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (ДополнительныеСведения.Идентификатор = АдресныеОбъекты0.ДополнительныеАдресныеСведения)
	|ГДЕ
	|	МуниципальнаяИерархия0.Идентификатор = &Идентификатор
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	&ПредставлениеАдминистративный КАК ТипАдреса,
	|	АдресныеОбъекты5.Наименование КАК Наименование5,
	|	АдресныеОбъекты5.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныеОбъекты5.Идентификатор КАК Идентификатор5,
	|	АдресныеОбъекты5.Уровень КАК Уровень5,
	|	АдресныеОбъекты4.Наименование КАК Наименование4,
	|	АдресныеОбъекты4.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныеОбъекты4.Идентификатор КАК Идентификатор4,
	|	АдресныеОбъекты4.Уровень КАК Уровень4,
	|	АдресныеОбъекты3.Наименование КАК Наименование3,
	|	АдресныеОбъекты3.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныеОбъекты3.Идентификатор КАК Идентификатор3,
	|	АдресныеОбъекты3.Уровень КАК Уровень3,
	|	АдресныеОбъекты2.Наименование КАК Наименование2,
	|	АдресныеОбъекты2.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныеОбъекты2.Идентификатор КАК Идентификатор2,
	|	АдресныеОбъекты2.Уровень КАК Уровень2,
	|	АдресныеОбъекты1.Наименование КАК Наименование1,
	|	АдресныеОбъекты1.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныеОбъекты1.Идентификатор КАК Идентификатор1,
	|	АдресныеОбъекты1.Уровень КАК Уровень1,
	|	АдресныеОбъекты0.Наименование КАК Наименование0,
	|	АдресныеОбъекты0.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныеОбъекты0.Идентификатор КАК Идентификатор0,
	|	АдресныеОбъекты0.Уровень КАК Уровень0,
	|	АдресныеОбъекты0.КодКЛАДР КАК КодКЛАДР,
	|	АдресныеОбъекты0.КодСубъектаРФ КАК КодСубъектаРФ,
	|	ЕСТЬNULL(ДополнительныеСведения.ПочтовыйИндекс, """") КАК ПочтовыйИндекс,
	|	ЕСТЬNULL(ДополнительныеСведения.ОКТМО, """") КАК ОКТМО,
	|	ЕСТЬNULL(ДополнительныеСведения.OKATO, """") КАК OKATO,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСЮЛ, """") КАК КодУчасткаИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСФЛ, """") КАК КодУчасткаИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСЮЛ, """") КАК КодИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСФЛ, """") КАК КодИФНСФЛ
	|ИЗ
	|	РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия0
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия1
	|		ПО (АдминистративнаяИерархия0.РодительскийИдентификатор = АдминистративнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия2
	|		ПО (АдминистративнаяИерархия1.РодительскийИдентификатор = АдминистративнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия3
	|		ПО (АдминистративнаяИерархия2.РодительскийИдентификатор = АдминистративнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия4
	|		ПО (АдминистративнаяИерархия3.РодительскийИдентификатор = АдминистративнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия5
	|		ПО (АдминистративнаяИерархия4.РодительскийИдентификатор = АдминистративнаяИерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты0
	|		ПО (АдресныеОбъекты0.Идентификатор = АдминистративнаяИерархия0.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты1
	|		ПО (АдресныеОбъекты1.Идентификатор = АдминистративнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты2
	|		ПО (АдресныеОбъекты2.Идентификатор = АдминистративнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты3
	|		ПО (АдресныеОбъекты3.Идентификатор = АдминистративнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты4
	|		ПО (АдресныеОбъекты4.Идентификатор = АдминистративнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты5
	|		ПО (АдресныеОбъекты5.Идентификатор = АдминистративнаяИерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (ДополнительныеСведения.Идентификатор = АдресныеОбъекты0.ДополнительныеАдресныеСведения)
	|ГДЕ
	|	АдминистративнаяИерархия0.Идентификатор = &Идентификатор
	|";

	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("ПредставлениеМуниципальный", МуниципальныйАдрес());
	Запрос.УстановитьПараметр("ПредставлениеАдминистративный", АдминистративноТерриториальныйАдрес());
	Запрос.УстановитьПараметр("Идентификатор", Новый УникальныйИдентификатор(СведенияОбАдресномОбъекте.Идентификатор));
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		
		Результат = АдресПоИдентификаторуРегионаИзЗагруженныхДанных(СведенияОбАдресномОбъекте);
	
		Возврат;
	КонецЕсли;
	
	Результат = ОписаниеНовойКонтактнойИнформации();

	Выборка = РезультатЗапроса.Выгрузить();

	Результат.addressType = ?(СведенияОбАдресномОбъекте.Муниципальный, МуниципальныйАдрес(),
		АдминистративноТерриториальныйАдрес());
	
	СловарьИменПолей = СловарьКлючейПолейАдресВСоответствииСУровнем();

	АдминистративныйАдрес = Неопределено;
	МуниципальныйАдрес    = Неопределено;

	ПоляТекущегоАдреса = Новый Структура;

	Если ЗначениеЗаполнено(СведенияОбАдресномОбъекте.Адрес) Тогда
		
		ТекущийАдреса = СведенияОбАдресномОбъекте.Адрес;
		
		ПорядокУровней = ИменаУровнейАдреса(ТекущийАдреса, Истина, Истина);
		
		Для Каждого ТекущийУровеньАдреса Из ПорядокУровней Цикл
			
			Если ЗначениеЗаполнено(ТекущийАдреса[ТекущийУровеньАдреса]) Тогда
				ПоляТекущегоАдреса.Вставить(ТекущийУровеньАдреса, ТекущийАдреса[ТекущийУровеньАдреса]);
				ПоляТекущегоАдреса.Вставить(ТекущийУровеньАдреса + "Type", ТекущийАдреса[ТекущийУровеньАдреса + "Type"]);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	МуниципальныйАдресНайден = Ложь;
	Для Каждого АдресИзВыборки Из Выборка Цикл
		Если АдресИзВыборки.ТипАдреса = МуниципальныйАдрес() И МуниципальныйАдресНайден = Ложь Тогда
			МуниципальныйАдрес = АдресИзВыборки;

			Если ПоляТекущегоАдреса.Количество() = 0 Тогда
				МуниципальныйАдресНайден = Истина;
			КонецЕсли;

			ПоляНайденногоАдреса = Новый Структура;

			Для Позиция = 0 По 5 Цикл
				Если ПустаяСтрока(МуниципальныйАдрес["Уровень" + Строка(Позиция)]) Тогда
					Прервать;
				КонецЕсли;

				ИмяУровня = СловарьИменПолей[МуниципальныйАдрес["Уровень" + Строка(Позиция)]];

				ПоляНайденногоАдреса.Вставить(ИмяУровня, МуниципальныйАдрес["Наименование" + Строка(Позиция)]);
				ПоляНайденногоАдреса.Вставить(ИмяУровня + "Type", МуниципальныйАдрес["ТипОбъекта" + Строка(Позиция)]);

			КонецЦикла;

			Если СравнитьПоляАдреса(ПоляТекущегоАдреса, ПоляНайденногоАдреса) Тогда
				МуниципальныйАдресНайден = Истина;
				Продолжить;
			КонецЕсли;

		Иначе
			АдминистративныйАдрес = АдресИзВыборки;
		КонецЕсли;

	КонецЦикла;

	ПорядокАдминистративныхПолей = Новый Массив;
	Если АдминистративныйАдрес <> Неопределено Тогда

		Индекс = 5;
		Пока Индекс >= 0 Цикл
			ЗаполнитьПоляВСоответствииСУровнемАдреса(Результат, АдминистративныйАдрес, Индекс, СловарьИменПолей,
				ЭтоМуниципальныйАдрес(АдминистративныйАдрес.ТипАдреса), ПорядокАдминистративныхПолей);
			Индекс = Индекс - 1;
		КонецЦикла;
		Результат.admLevels = ПорядокАдминистративныхПолей;

	КонецЕсли;
	
	// Муниципальный
	ПорядокМуниципальныхПолей = Новый Массив;
	Если МуниципальныйАдрес <> Неопределено Тогда
		Индекс = 5;
		Пока Индекс >= 0 Цикл
			ЗаполнитьПоляВСоответствииСУровнемАдреса(Результат, МуниципальныйАдрес, Индекс, СловарьИменПолей,
				ЭтоМуниципальныйАдрес(
				МуниципальныйАдрес.ТипАдреса), ПорядокМуниципальныхПолей);
			Индекс = Индекс - 1;
		КонецЦикла;
	КонецЕсли;
	Результат.munLevels = ПорядокМуниципальныхПолей;

	Если АдминистративныйАдрес <> Неопределено И МуниципальныйАдрес <> Неопределено Тогда
		СтрокаКодов = ?(Результат["addressType"] = АдминистративноТерриториальныйАдрес(), АдминистративныйАдрес,
			МуниципальныйАдрес);
	ИначеЕсли АдминистративныйАдрес = Неопределено Тогда
		СтрокаКодов = МуниципальныйАдрес;
	Иначе
		СтрокаКодов = АдминистративныйАдрес;
	КонецЕсли;

	Если СтрокаКодов = Неопределено Тогда
		Результат.areaValue      = СоединитьНаименованиеИТипАдресногоОбъекта(Результат.area, Результат.areaType, Истина);
		Возврат;
	КонецЕсли;
	
	Результат.ZipCode        = Формат(СтрокаКодов.ПочтовыйИндекс, "ЧГ=0");
	Результат.OKTMO          = Формат(СтрокаКодов.ОКТМО, "ЧГ=0");
	Результат.OKATO          = Формат(СтрокаКодов.OKATO, "ЧГ=0");
	Результат.IFNSULAreaCode = СтрокаКодов.КодУчасткаИФНСЮЛ;
	Результат.IFNSFLAreaCode = СтрокаКодов.КодУчасткаИФНСФЛ;
	Результат.IFNSULCode     = СтрокаКодов.КодИФНСЮЛ;
	Результат.IFNSFLCode     = СтрокаКодов.КодИФНСФЛ;
	Результат.areaValue      = ПолноеНаименованиеРегионаПоКоду(СтрокаКодов.КодСубъектаРФ);

КонецПроцедуры

// Параметры:
//  СведенияОбАдресномОбъекте - см. СведенияОбАдресномОбъекта
// 
// Возвращаемое значение:
//   см. ОписаниеНовойКонтактнойИнформации
//
Функция АдресПоИдентификаторуРегионаИзЗагруженныхДанных(СведенияОбАдресномОбъекте)
	
	Результат = ОписаниеНовойКонтактнойИнформации();
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
	|	АдресныеОбъекты.Наименование КАК Наименование,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
	|	АдресныеОбъекты.КодКЛАДР КАК КодКЛАДР
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|ГДЕ
	|	АдресныеОбъекты.Идентификатор = &Идентификатор
	|	И АдресныеОбъекты.Уровень = 1";
	
	Запрос.УстановитьПараметр("Идентификатор", Новый УникальныйИдентификатор(СведенияОбАдресномОбъекте.Идентификатор));
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если Не РезультатЗапроса.Пустой() Тогда
		
		СтрокаДанных          = РезультатЗапроса.Выгрузить()[0];
		Результат.area        = СтрокаДанных.Наименование;
		Результат.areaType    = СтрокаДанных.ТипОбъекта;
		Результат.areaCode    = СтрокаДанных.КодСубъектаРФ;
		Результат.areaId      = СведенияОбАдресномОбъекте.Идентификатор;
		Результат.areaValue   = ПолноеНаименованиеРегионаПоКоду(СтрокаДанных.КодСубъектаРФ);
		Результат.munLevels   = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве("area");
		Результат.admLevels   = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве("area");
		Результат.addressType = ?(СведенияОбАдресномОбъекте.Муниципальный, МуниципальныйАдрес(),
			АдминистративноТерриториальныйАдрес());
		Результат.codeKLADR   = СтрокаДанных.КодКЛАДР;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция СравнитьПоляАдреса(ТекущийАдрес, НайденныйАдрес)

	Для Каждого КлючИЗначение Из ТекущийАдрес Цикл

		Если Не НайденныйАдрес.Свойство(КлючИЗначение.Ключ) Или СтрСравнить(КлючИЗначение.Значение,
			НайденныйАдрес[КлючИЗначение.Ключ]) <> 0 Тогда
			Возврат Ложь;
		КонецЕсли;

	КонецЦикла;

	Возврат Истина;

КонецФункции

Функция АктуальныйАдресДляИсторического(Адрес)
	
	РезультатПоиска = Новый Структура;
	РезультатПоиска.Вставить("АдресНайден",   Ложь);
	РезультатПоиска.Вставить("Варианты",      Новый Массив);
	РезультатПоиска.Вставить("Представление", "");
	
	Запрос = Новый Запрос;
	ШаблонТекстаСоединения = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ИсторияАдресныхОбъектов.Идентификатор КАК Идентификатор,
	|	ИсторияАдресныхОбъектов.АдресныйОбъект КАК АдресныйОбъект,
	|	ИсторияАдресныхОбъектов.Уровень КАК Уровень,
	|	ИсторияАдресныхОбъектов.ОкончаниеДействияЗаписи КАК ОкончаниеДействияЗаписи
	|ИЗ
	|	РегистрСведений.ИсторияАдресныхОбъектов КАК ИсторияАдресныхОбъектов
	|ГДЕ
	|	ИсторияАдресныхОбъектов.КодСубъектаРФ = &КодСубъектаРФ
	|	И ИсторияАдресныхОбъектов.Наименование = &Наименование0
	|	И ИсторияАдресныхОбъектов.ТипОбъекта = &ТипОбъекта0
	|
	|УПОРЯДОЧИТЬ ПО
	|	ОкончаниеДействияЗаписи УБЫВ";
	
	ИменаУровнейАдреса = ИменаУровнейАдреса(Адрес, Истина);
	Счетчик = 0;

	ТекстСоединения = "";

	КоличествоУровней = ИменаУровнейАдреса.Количество() - 1;
	Пока КоличествоУровней >= 0 Цикл
		УровеньАдреса = ИменаУровнейАдреса[КоличествоУровней];

		Если Адрес.Свойство(УровеньАдреса) И ЗначениеЗаполнено(Адрес[УровеньАдреса]) Тогда
			
			ТекстСоединения = ТекстСоединения + СтрЗаменить(ШаблонТекстаСоединения, 
				"0", Счетчик) + ОбщегоНазначения.РазделительПакетаЗапросов();

			Запрос.УстановитьПараметр("Наименование" + XMLСтрока(Счетчик), Адрес[УровеньАдреса]);
			Запрос.УстановитьПараметр("ТипОбъекта" + XMLСтрока(Счетчик), Адрес[УровеньАдреса + "Type"]);

			Счетчик = Счетчик + 1;

		КонецЕсли;
		КоличествоУровней = КоличествоУровней - 1;

	КонецЦикла;
	
	КодСубъектаРФ = АдресныйКлассификатор.КодРегионаПоНаименованию(СоединитьНаименованиеИТипАдресногоОбъекта(
		Адрес.Area, Адрес.AreaType, Истина));
		
	Если ПустаяСтрока(ТекстСоединения) Или КодСубъектаРФ = Неопределено Тогда
		Возврат РезультатПоиска;
	КонецЕсли;
	
	Запрос.Текст = ТекстСоединения;
	Запрос.УстановитьПараметр("КодСубъектаРФ", КодСубъектаРФ);
	
	НаборРезультатовЗапроса = Запрос.ВыполнитьПакет();
	
	ИдентификаторАдресногоОбъекта = Неопределено;
	Для Каждого РезультатЗапроса Из НаборРезультатовЗапроса Цикл
		Если РезультатЗапроса.Пустой() Тогда
			Продолжить;
		КонецЕсли;
		ДанныеОбАдресномОбъекта = РезультатЗапроса.Выгрузить();
		ИдентификаторАдресногоОбъекта = ДанныеОбАдресномОбъекта[0].АдресныйОбъект;
		Прервать;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(ИдентификаторАдресногоОбъекта) Тогда
		
		СведенияОбАдресномОбъекта = СведенияОбАдресномОбъекта(ИдентификаторАдресногоОбъекта);
		СведенияОбАдресномОбъекта.Адрес             = Адрес;
		СведенияОбАдресномОбъекта.ЗагруженныеДанные = Истина;
		СведенияОбАдресномОбъекта.Муниципальный     = ЭтоМуниципальныйАдрес(Адрес.AddressType);
		
		НайденныйАдрес = АктуальныеАдресныеСведения(СведенияОбАдресномОбъекта);
		Если НайденныйАдрес.Отказ Тогда
			Возврат РезультатПоиска;
		КонецЕсли;
		
		АктуальныйАдрес = НайденныйАдрес.Данные;
		
		НовыйАдрес = ОбщегоНазначения.СкопироватьРекурсивно(Адрес);
		ИменаУровней = ИменаУровнейАдресаПоКоду();
		
		ИмяУровнейНаселенногоПункта = ИмяУровнейНаселенногоПункта();
		ОтсутствуютПоляНаселенногоПункта = Истина;
		Для Каждого ИмяУровня Из ИменаУровней Цикл 
			
			Если ОтсутствуютПоляНаселенногоПункта = Истина
				И ИмяУровнейНаселенногоПункта[ИмяУровня.Значение] <> Неопределено
				И ЗначениеЗаполнено(АктуальныйАдрес[ИмяУровня.Значение]) Тогда
				ОтсутствуютПоляНаселенногоПункта = Ложь;
			КонецЕсли;
			
			НовыйАдрес[ИмяУровня.Значение]          = АктуальныйАдрес[ИмяУровня.Значение];
			НовыйАдрес[ИмяУровня.Значение + "Type"] = АктуальныйАдрес[ИмяУровня.Значение + "Type"];
			НовыйАдрес[ИмяУровня.Значение + "Id"]   = АктуальныйАдрес[ИмяУровня.Значение + "Id"];
		КонецЦикла;
		
		Если ОтсутствуютПоляНаселенногоПункта = Истина Тогда
			Если ЭтоМуниципальныйАдрес(Адрес.AddressType) Тогда
				Возврат РезультатПоиска;
			Иначе
				Регион = СоединитьНаименованиеИТипАдресногоОбъекта(НовыйАдрес.area, НовыйАдрес.areaType, Истина);
				Если Не ЭтоГородФедеральногоЗначения(Регион) Тогда
					Возврат РезультатПоиска;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		НовыйАдрес.value  = "";
		ЗаполнитьЗначенияСвойств(НовыйАдрес, АктуальныйАдрес, "munLevels,admLevels,areaValue");
		
		РезультатПоиска.Варианты.Добавить(НовыйАдрес);
		
		ПредставлениеАдреса = ПредставлениеАдреса(НовыйАдрес);
		РезультатПоиска.Представление = ПредставлениеАдреса;
		РезультатПоиска.АдресНайден = Истина;
	
	КонецЕсли;
	
	Возврат РезультатПоиска;
	
КонецФункции

Функция ПредставлениеАдреса(Адрес, ТипАдреса = Неопределено) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
		Возврат МодульРаботаСАдресамиКлиентСервер.ПредставлениеАдреса(Адрес, Ложь, ТипАдреса);
	КонецЕсли;
	
	ТипАдреса = Адрес.AddressType;
	
	СписокЗаполненныхУровней = Новый Массив;
	
	Если Адрес.Свойство("zipCode") И НЕ ПустаяСтрока(Адрес.ZipCode) Тогда
		СписокЗаполненныхУровней.Добавить(Адрес.ZipCode);
	КонецЕсли;
	
	ПорядокУровнейВАдресе = Новый Массив;
	Если ЭтоМуниципальныйАдрес(ТипАдреса) И ЗначениеЗаполнено(Адрес.munLevels) Тогда
			ПорядокУровнейВАдресе = Адрес.munLevels;
	ИначеЕсли ЭтоАдминистративноТерриториальныйАдрес(ТипАдреса) И ЗначениеЗаполнено(Адрес.admLevels) Тогда
			ПорядокУровнейВАдресе = Адрес.admLevels;
	КонецЕсли;
		
	Если ПорядокУровнейВАдресе.Количество() = 0 Тогда
		ПорядокУровнейВАдресе = ИменаУровнейАдреса(ТипАдреса, Истина);
	КонецЕсли;

	Для каждого ИмяУровня Из ПорядокУровнейВАдресе Цикл
		
		Если ЗначениеЗаполнено(Адрес[ИмяУровня]) Тогда
			
			Если СтрСравнить(ИмяУровня, "munDistrict") = 0 Тогда
				Адрес[ИмяУровня] = КраткоеНаписаниеМуниципальныхРайонов(Адрес[ИмяУровня], Адрес[ИмяУровня + "Type"]);
			КонецЕсли;
			
			Если СтрСравнить(ИмяУровня, "settlement") = 0 Тогда
				Адрес[ИмяУровня] = КраткоеНаписаниеПоселений(Адрес[ИмяУровня], Адрес[ИмяУровня + "Type"]);
			КонецЕсли;
			
			СписокЗаполненныхУровней.Добавить(ПредставлениеУровняАдреса(Адрес, ИмяУровня));
			
		КонецЕсли;
		
	КонецЦикла;
	
	Если Адрес.Свойство("houseNumber") И НЕ ПустаяСтрока(Адрес.HouseNumber) Тогда
		
		СписокЗаполненныхУровней.Добавить(СоединитьНомерИТипЗдания(Адрес.HouseNumber, Адрес.HouseType));
		
	ИначеЕсли Адрес.Свойство("stead") И Не ПустаяСтрока(Адрес.stead) Тогда
		
		СписокЗаполненныхУровней.Добавить(
			СоединитьНомерИТипЗдания(Адрес.stead, НаименованиеЗемельногоУчастка()));
			
	КонецЕсли;
	
	Если Адрес.Свойство("Buildings") И Адрес.Buildings.Количество() > 0 Тогда
		
		Для каждого Строение Из Адрес.Buildings Цикл
			Если ЗначениеЗаполнено(Строение.Number) Тогда
				
				СписокЗаполненныхУровней.Добавить(СоединитьНомерИТипЗдания(Строение.Number, Строение.Type));
				
			КонецЕсли;
		КонецЦикла;
		
	КонецЕсли;
	
	Если Адрес.Свойство("Apartments")
		И Адрес.Apartments <> Неопределено
		И Адрес.Apartments.Количество() > 0 Тогда
		
		Для каждого Строение Из Адрес.Apartments Цикл
			Если ЗначениеЗаполнено(Строение.Number) Тогда
				Если СтрСравнить(Строение.Type, "Другое") <> 0 Тогда
					СписокЗаполненныхУровней.Добавить(СоединитьНомерИТипЗдания(Строение.Number, Строение.Type));
				Иначе
					СписокЗаполненныхУровней.Добавить(Строение.Number);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
	КонецЕсли;
	
	Представление = СтрСоединить(СписокЗаполненныхУровней, ", ");
	
	Возврат Представление;
	
КонецФункции

Функция НаименованиеЗемельногоУчастка() Экспорт
	// АПК: 1036-выкл Данные адресного классификатора, не локализуются
	Возврат "Зем. участок";
	// АПК: 1036-вкл
КонецФункции

Функция ПредставлениеУровняАдреса(Адрес, ИмяУровня) Экспорт
	
	ЭтоРегион = СтрСравнить(ИмяУровня, АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().area) = 0;
	Если ЭтоРегион И ЗначениеЗаполнено(Адрес["areaValue"]) Тогда
		Возврат Адрес["areaValue"];
	КонецЕсли;
		
	Возврат СоединитьНаименованиеИТипАдресногоОбъекта(Адрес[ИмяУровня], Адрес[ИмяУровня + "Type"], ЭтоРегион);
	
КонецФункции

Функция СоединитьНомерИТипЗдания(Знач Номер, Знач ТипЗданияИлиПомещения)
	
	Если ПустаяСтрока(ТипЗданияИлиПомещения) Тогда
		Возврат Номер;
	КонецЕсли;
	

	Возврат ТРег(ТипЗданияИлиПомещения) + " "+ Номер;
КонецФункции

// Параметры:
//  Результат - см. СведенияОЗагруженномРегионе
//  Наименование - Строка
//  ТипОбъекта - Строка
// 
Процедура ПроверкаНаУстаревшийРегион(Результат, Наименование, ТипОбъекта) Экспорт

	НаименованиеРегиона = СоединитьНаименованиеИТипАдресногоОбъекта(Наименование, ТипОбъекта, Истина);
	Если СтрСравнить(ИсторическоеНаименованиеКемеровскойОбласти(), НаименованиеРегиона) = 0 Тогда
		Результат.Устарел            = Истина;
		Результат.КодСубъектаРФ      = 42;
		Результат.ПолноеНаименование = НаименованиеРегиона;
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ИсторияАдресныхОбъектов.КодСубъектаРФ КАК КодСубъектаРФ
	|ИЗ
	|	РегистрСведений.ИсторияАдресныхОбъектов КАК ИсторияАдресныхОбъектов
	|ГДЕ
	|	ИсторияАдресныхОбъектов.Наименование = &Наименование
	|	И ИсторияАдресныхОбъектов.ТипОбъекта = &ТипОбъекта
	|	И ИсторияАдресныхОбъектов.Уровень = 1
	|
	|УПОРЯДОЧИТЬ ПО
	|	ИсторияАдресныхОбъектов.ОкончаниеДействияЗаписи УБЫВ";

	Запрос.УстановитьПараметр("Наименование", Наименование);
	Запрос.УстановитьПараметр("ТипОбъекта", ТипОбъекта);

	РезультатЗапроса = Запрос.Выполнить().Выбрать();
	
	Пока РезультатЗапроса.Следующий() Цикл
		Результат.Устарел            = Истина;
		Результат.КодСубъектаРФ      = РезультатЗапроса.КодСубъектаРФ;
		Результат.ПолноеНаименование = НаименованиеРегиона;
	КонецЦикла;

КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * Загружен - Булево
//   * Устарел - Булево
//   * КодСубъектаРФ - Неопределено
//   * ПолноеНаименование - Строка
// 
Функция СведенияОЗагруженномРегионе() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Загружен", Ложь);
	Результат.Вставить("Устарел", Ложь);
	Результат.Вставить("КодСубъектаРФ", Неопределено);
	Результат.Вставить("ПолноеНаименование", "");
	
	Возврат Результат;
	
КонецФункции


// Возвращаемое значение:
//  Структура:
//   * Идентификатор - Строка
//   * Родитель - Строка
//   * Отказ - Булево
//   * ЗагруженныеДанные - Булево
//   * Представление - Строка 
//   * Уровень - Число
//   * Наименование - Строка
//   * ТипОбъекта - Строка
//   * ПредлагатьЗагрузкуКлассификатора - Булево
//
Функция СведенияОбПодбираемомАдресномОбъекте()
	
	Сведения = Новый Структура;
	Сведения.Вставить("Идентификатор",                    "");
	Сведения.Вставить("Родитель",                         "");
	Сведения.Вставить("Отказ",                            Ложь);
	Сведения.Вставить("ЗагруженныеДанные",                Ложь);
	Сведения.Вставить("Представление",                    "");
	Сведения.Вставить("Уровень",                          0);
	Сведения.Вставить("Наименование",                     "");
	Сведения.Вставить("ТипОбъекта",                       "");
	Сведения.Вставить("ПредлагатьЗагрузкуКлассификатора", Ложь);
	Возврат Сведения;
	
КонецФункции

// Параметры:
//   Наименование - Строка
//   ТипОбъекта - Строка 
// 
// Возвращаемое значение:
//  РезультатЗапроса
//  Неопределено
//
Функция АктуальныеДанныеОРегионе(Знач Наименование, ТипОбъекта = "") Экспорт

	Запрос = Новый Запрос;

	Если ЗначениеЗаполнено(ТипОбъекта) Тогда

		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
		|	ВЫБОР
		|		КОГДА НЕ ЗагруженныеДанные.Идентификатор ЕСТЬ NULL 
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК РегионЗагружен
		|ИЗ
		|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК ЗагруженныеДанные
		|		ПО (ЗагруженныеДанные.Уровень > 1)
		|			И АдресныеОбъекты.КодСубъектаРФ = ЗагруженныеДанные.КодСубъектаРФ
		|ГДЕ
		|	АдресныеОбъекты.Наименование = &Наименование
		|	И АдресныеОбъекты.ТипОбъекта = &ТипОбъекта
		|	И АдресныеОбъекты.Уровень = 1";

		Запрос.УстановитьПараметр("ТипОбъекта", ТипОбъекта);

	Иначе

		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
		|	ВЫБОР
		|		КОГДА НЕ ЗагруженныеДанные.Идентификатор ЕСТЬ NULL 
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК РегионЗагружен
		|ИЗ
		|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК ЗагруженныеДанные
		|		ПО (ЗагруженныеДанные.Уровень > 1)
		|			И АдресныеОбъекты.КодСубъектаРФ = ЗагруженныеДанные.КодСубъектаРФ
		|ГДЕ
		|	АдресныеОбъекты.Наименование = &Наименование
		|	И АдресныеОбъекты.Уровень = 1";

	КонецЕсли;

	Запрос.УстановитьПараметр("Наименование", Наименование);

	РезультатЗапроса = Запрос.Выполнить();
	Возврат РезультатЗапроса;

КонецФункции

Функция КодыПоИдентификаторуАдресногоОбъекта(АдресныйОбъект, СведенияОДоме)

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ДомаЗданияСтроения.Строения КАК Строения,
	|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	ДополнительныеСведения.ОКТМО КАК ОКТМО,
	|	ДополнительныеСведения.ОКТМОБюджетополучателя КАК ОКТМОБюджетополучателя,
	|	ДополнительныеСведения.OKATO КАК ОКАТО,
	|	ДополнительныеСведения.КодУчасткаИФНСЮЛ КАК КодУчасткаИФНСЮЛ,
	|	ДополнительныеСведения.КодУчасткаИФНСФЛ КАК КодУчасткаИФНСФЛ,
	|	ДополнительныеСведения.КодИФНСЮЛ КАК КодИФНСЮЛ,
	|	ДополнительныеСведения.КодИФНСФЛ КАК КодИФНСФЛ
	|ИЗ
	|	РегистрСведений.ДомаЗданияСтроения КАК ДомаЗданияСтроения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО ДомаЗданияСтроения.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор
	|ГДЕ
	|	ДомаЗданияСтроения.АдресныйОбъект = &АдресныйОбъект";

	Запрос.УстановитьПараметр("АдресныйОбъект", АдресныйОбъект);
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();

	ОписаниеДома = НайтиСтрокуСДомом(РезультатЗапроса, СведенияОДоме);

	Если ОписаниеДома <> Неопределено Тогда
		
		Возврат ОписаниеДома;

	Иначе
		// Коды с точностью до дома не найдены. Поэтому используем коды адресного объекта
		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ
		|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
		|	ДополнительныеСведения.ОКТМО КАК ОКТМО,
		|	ДополнительныеСведения.ОКТМОБюджетополучателя КАК ОКТМОБюджетополучателя,
		|	ДополнительныеСведения.OKATO КАК ОКАТО,
		|	ДополнительныеСведения.КодУчасткаИФНСЮЛ КАК КодУчасткаИФНСЮЛ,
		|	ДополнительныеСведения.КодУчасткаИФНСФЛ КАК КодУчасткаИФНСФЛ,
		|	ДополнительныеСведения.КодИФНСЮЛ КАК КодИФНСЮЛ,
		|	ДополнительныеСведения.КодИФНСФЛ КАК КодИФНСФЛ
		|ИЗ
		|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
		|		ПО АдресныеОбъекты.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор
		|ГДЕ
		|	АдресныеОбъекты.Идентификатор = &АдресныйОбъект";

		Запрос.УстановитьПараметр("АдресныйОбъект", АдресныйОбъект);

		РезультатЗапроса = Запрос.Выполнить();

		Если Не РезультатЗапроса.Пустой() Тогда

			Результат = РезультатЗапроса.Выгрузить()[0];
			Коды = ОбщегоНазначения.СтрокаТаблицыЗначенийВСтруктуру(Результат);
			Коды.Вставить("ИдентификаторДома", "");

		КонецЕсли;
	КонецЕсли;

	Возврат Коды;

КонецФункции

Функция НайтиСтрокуСДомом(Знач Дома, Знач ДомВАдресе)

	Для Каждого ИнформацияОДомах Из Дома Цикл

		Если Не ЗначениеЗаполнено(ИнформацияОДомах.Строения) Тогда
			Продолжить;
		КонецЕсли;

		СтрокаСоСпискомДомов = ИнформацияОДомах.Строения.Получить();
		Если ЗначениеЗаполнено(СтрокаСоСпискомДомов) Тогда

			МассивДомов = СтрРазделить(СтрокаСоСпискомДомов, Символы.ПС, Ложь);

			Для Каждого СтрокаДом Из МассивДомов Цикл
				ОписаниеДома = ОписаниеДома(СтрокаДом);

				Если СтрСравнить(ДомВАдресе.НомерДома, ОписаниеДома.НомерДома) = 0 И СтрСравнить(
					ДомВАдресе.НаименованиеДома, ОписаниеДома.НаименованиеДома) = 0 Тогда

					Если СтрСравнить(ДомВАдресе.ДополнительныйНомерДома1, ОписаниеДома.ДополнительныйНомерДома1) = 0
						И СтрСравнить(ДомВАдресе.НаименованиеДополнительногоДома1,
						ОписаниеДома.НаименованиеДополнительногоДома1) = 0 И СтрСравнить(
						ДомВАдресе.ДополнительныйНомерДома2, ОписаниеДома.ДополнительныйНомерДома2) = 0 И СтрСравнить(
						ДомВАдресе.НаименованиеДополнительногоДома2, ОписаниеДома.НаименованиеДополнительногоДома2) = 0 Тогда

						ЗаполнитьЗначенияСвойств(ОписаниеДома, ИнформацияОДомах);
						ОписаниеДома.Индекс = ИнформацияОДомах.ПочтовыйИндекс;
						
						Возврат ОписаниеДома;

					КонецЕсли;

				КонецЕсли;

			КонецЦикла;

		КонецЕсли;

	КонецЦикла;

	Возврат Неопределено;

КонецФункции

Функция НайтиСтрокуСЗемельнымУчастком(Знач ЗемельныеУчастки, Знач ЗемельныйУчастокВАдресе)

	Результат = Новый Структура();
	Результат.Вставить("ИдентификаторУчастка",   Неопределено);
	Результат.Вставить("НомерЗемельногоУчастка", ЗемельныйУчастокВАдресе);
	
	Для Каждого ИнформацияОбУчастках Из ЗемельныеУчастки Цикл

		Если Не ЗначениеЗаполнено(ИнформацияОбУчастках.Участки) Тогда
			Продолжить;
		КонецЕсли;

		СтрокаСоСпискомУчастков = ИнформацияОбУчастках.Участки.Получить();
		Если ЗначениеЗаполнено(СтрокаСоСпискомУчастков) Тогда

			ПорцияЗемельныхУчастков = СтрРазделить(СтрокаСоСпискомУчастков, Символы.ПС, Ложь);

			Для Каждого СтрокаЗемельногоУчастка Из ПорцияЗемельныхУчастков Цикл
				
				НомерЗемельногоУчастка = Сред(СтрокаЗемельногоУчастка, 25);
				
				Если СтрСравнить(НомерЗемельногоУчастка, ЗемельныйУчастокВАдресе) = 0 Тогда
					Результат.ИдентификаторУчастка = УникальныйИдентификаторИзСтроки64(Лев(СтрокаЗемельногоУчастка, 24));
					Результат.НомерЗемельногоУчастка = Сред(СтрокаЗемельногоУчастка, 25);
					
					Возврат Результат;
				КонецЕсли;

			КонецЦикла;

		КонецЕсли;

	КонецЦикла;

	Возврат Результат;

КонецФункции

// Заполнение данных для автоподбора из загруженных данных.
//
Процедура ЗаполнитьСписокАвтоподбораПоЗагруженнымДанным(Результат, КешПредставлений, Знач Текст, ДополнительныеПараметры,
	ЗагруженныеАдресныеСведения)

	ПреобразоватьВводАдреса(Текст);
	ТекстПоиска = ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(Текст);

	Запрос = Новый Запрос;

	Если ДополнительныеПараметры.Свойство("Уровень") Тогда

		ТекстЗапроса = ОдноуровневыйАвтоподборНаселенногоПункта(ДополнительныеПараметры.ТипАдреса,
			ДополнительныеПараметры.Уровень);

		Запрос.УстановитьПараметр("Уровень", ДополнительныеПараметры.Уровень);
		Если ДополнительныеПараметры.Уровень > 1 Тогда
			Запрос.УстановитьПараметр("Идентификатор", ДополнительныеПараметры.Идентификатор);
		КонецЕсли;

	Иначе

		ТекстЗапроса = КаскадныйСписокАвтоподбораНаселенногоПункта(ДополнительныеПараметры.ТипАдреса);
		Приоритеты = ТаблицаПриоритетовПриАвтоподборе(ДополнительныеПараметры.ТипАдреса);
		Запрос.УстановитьПараметр("Приоритеты", Приоритеты);

	КонецЕсли;

	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("НачалоФразы", ТекстПоиска + "%");
	Запрос.УстановитьПараметр("НачалоФразыСПробелом", "% " + ТекстПоиска + "%");

	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;

	Результат = Новый СписокЗначений;

	Для Каждого СтрокаАдреса Из РезультатЗапроса.Выгрузить() Цикл

		НаборПредставление = Новый Массив;
		Для Позиция = 0 По 5 Цикл
			ПозицияСтрокой = Строка(Позиция);
			Наименование = СтрокаАдреса["Наименование" + ПозицияСтрокой];
			Если ПустаяСтрока(Наименование) Тогда
				Прервать;
			КонецЕсли;

			Если ЭтоУровеньРегиона(СтрокаАдреса["Уровень" + ПозицияСтрокой]) Тогда

				ПредставлениеУровня = ПолноеНаименованиеРегионаПоКоду(СтрокаАдреса.КодСубъектаРФ);

				Если Не ЗначениеЗаполнено(ПредставлениеУровня) Тогда
					ПредставлениеУровня = СоединитьНаименованиеИТипАдресногоОбъекта(Наименование,
						СтрокаАдреса["ТипОбъекта" + ПозицияСтрокой], Истина);
				КонецЕсли;
			Иначе

				ПредставлениеУровня = СоединитьНаименованиеИТипАдресногоОбъекта(Наименование, СтрокаАдреса["ТипОбъекта"
					+ ПозицияСтрокой]);

			КонецЕсли;
			НаборПредставление.Добавить(ПредставлениеУровня);

		КонецЦикла;

		Представление = СтрСоединить(НаборПредставление, ", ");

		Если СтрокаАдреса.Уровень0 > 1 И ЗначениеЗаполнено(СтрокаАдреса.ПочтовыйИндекс) Тогда
			Представление = Представление + " (" + Формат(СтрокаАдреса.ПочтовыйИндекс, "ЧГ=0") + ")";
		КонецЕсли;

		ЭтоГородФедеральногоЗначения     = Ложь;
		ПредлагатьЗагрузкуКлассификатора = Ложь;

		Если ЭтоУровеньРегиона(СтрокаАдреса.Уровень0) Тогда
				
			ЭтоГородФедеральногоЗначения = ЭтоГородФедеральногоЗначения(Представление);
			Если Не ЗагруженныеАдресныеСведения.Получить("КлассификаторДоступен") Тогда

				КодРегиона = АдресныйКлассификатор.КодРегионаПоНаименованию(Представление);
				Если КодРегиона <> Неопределено Тогда
					ДанныеОРегионе = ЗагруженныеАдресныеСведения.Получить(КодРегиона);
					Если ТипЗнч(ДанныеОРегионе) = Тип("Структура") И ДанныеОРегионе.ИспользоватьЗагруженные = Ложь Тогда
						ПредлагатьЗагрузкуКлассификатора = Истина;
					КонецЕсли;
				КонецЕсли;

			КонецЕсли;
			
			СтрокаАдреса.Муниципальный = Истина;

		КонецЕсли;
		
		СловарьИменПолей = СловарьКлючейПолейАдресВСоответствииСУровнем();
		
		НайденныйАдрес = ОписаниеНовойКонтактнойИнформации();
		НайденныйАдрес.addressType = ?(СтрокаАдреса.Муниципальный, МуниципальныйАдрес(),
			АдминистративноТерриториальныйАдрес());
		
		ПорядокАдминистративныхПолей = Новый Массив;
		Если Не СтрокаАдреса.Муниципальный Тогда

			Индекс = 5;
			Пока Индекс >= 0 Цикл
				ЗаполнитьПоляВСоответствииСУровнемАдреса(НайденныйАдрес, СтрокаАдреса, Индекс, СловарьИменПолей, Ложь,
					ПорядокАдминистративныхПолей);
				Индекс = Индекс - 1;
			КонецЦикла;
			НайденныйАдрес.admLevels = ПорядокАдминистративныхПолей;

		Иначе

			ПорядокМуниципальныхПолей = Новый Массив;

			Индекс = 5;
			Пока Индекс >= 0 Цикл
				ЗаполнитьПоляВСоответствииСУровнемАдреса(НайденныйАдрес, СтрокаАдреса, Индекс, СловарьИменПолей,
					Истина, ПорядокМуниципальныхПолей);
				Индекс = Индекс - 1;
			КонецЦикла;
			НайденныйАдрес.munLevels = ПорядокМуниципальныхПолей;
		КонецЕсли;

		НайденныйАдрес.areaCode  = СтрокаАдреса.КодСубъектаРФ;
		НайденныйАдрес.areaValue = ПолноеНаименованиеРегионаПоКоду(СтрокаАдреса.КодСубъектаРФ);

		Сведения = СведенияОПодбираемомАдресе(Представление, СтрокаАдреса.Идентификатор0, СтрокаАдреса.Муниципальный,
			Истина, НайденныйАдрес, ПредлагатьЗагрузкуКлассификатора);
		ДобавитьВариантАдреса(Результат, КешПредставлений, Сведения, ЭтоГородФедеральногоЗначения);

	КонецЦикла;

КонецПроцедуры

Функция ЭтоУровеньРегиона(Уровень)
	Возврат Уровень = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().area;
КонецФункции

Функция ЭтоУровеньУлицы(Уровень)
	Возврат Уровень = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().street;
КонецФункции

Функция ТаблицаПриоритетовПриАвтоподборе(ТипАдреса)

	НомераУровнейАдресаПоНаименованию = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию();

	Приоритеты = Новый ТаблицаЗначений;
	Приоритеты.Колонки.Добавить("Уровень", ОбщегоНазначения.ОписаниеТипаЧисло(1));
	Приоритеты.Колонки.Добавить("Порядок", ОбщегоНазначения.ОписаниеТипаЧисло(1));

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.city;
	НоваяКолонка.Порядок = 1;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.area;
	НоваяКолонка.Порядок = 2;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.locality;
	НоваяКолонка.Порядок = 2;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.munDistrict;
	НоваяКолонка.Порядок = 2;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.settlement;
	НоваяКолонка.Порядок = 3;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.district;
	НоваяКолонка.Порядок = 3;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.territory;
	НоваяКолонка.Порядок = 5;

	НоваяКолонка = Приоритеты.Добавить();
	НоваяКолонка.Уровень = НомераУровнейАдресаПоНаименованию.street;
	НоваяКолонка.Порядок = 6;

	Возврат Приоритеты;

КонецФункции

// Преобразует введенные английские буквы к русской раскладке при подборе адреса
//
Процедура ПреобразоватьВводАдреса(Текст)
	РусскиеКлавиши = "ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЁ";
	АнглийскиеКлавиши = "QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,`";
	Текст = ВРег(Текст);
	Для Позиция = 0 По СтрДлина(Текст) Цикл
		Символ = Сред(Текст, Позиция, 1);
		ПозицияСимвола = СтрНайти(АнглийскиеКлавиши, Символ);
		Если ПозицияСимвола > 0 Тогда
			Текст = СтрЗаменить(Текст, Символ, Сред(РусскиеКлавиши, ПозицияСимвола, 1));
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Функция ОдноуровневыйАвтоподборНаселенногоПункта(ТипаАдреса, Уровень)

	ТекстЗапроса = 
	"ВЫБРАТЬ ПЕРВЫЕ 20
	|	&Представление КАК Представление,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеАдресныеСведения,
	|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	&Муниципальный КАК Муниципальный
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО АдресныеОбъекты.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор
	|ГДЕ
	|	(АдресныеОбъекты.Наименование ПОДОБНО &НачалоФразы СПЕЦСИМВОЛ ""~""
	|		ИЛИ АдресныеОбъекты.Наименование ПОДОБНО &НачалоФразыСПробелом СПЕЦСИМВОЛ ""~"")
	|	И АдресныеОбъекты.Уровень = &Уровень
	|	И &ОтборПоИдентификатору
	|
	|УПОРЯДОЧИТЬ ПО
	|	Представление";

	Если Уровень > 1 Тогда
		ОтборПоИдентификатору = "АдресныеОбъекты.МуниципальныйРодительскийИдентификатор = &Идентификатор";
		Представление = "АдресныеОбъекты.ТипОбъекта + "" "" + АдресныеОбъекты.Наименование";
	Иначе
		ОтборПоИдентификатору = "ИСТИНА";
		Представление = "АдресныеОбъекты.Наименование + "" "" + АдресныеОбъекты.ТипОбъекта";
	КонецЕсли;

	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Представление", Представление);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИдентификатору", ОтборПоИдентификатору);

	Если ЭтоМуниципальныйАдрес(ТипаАдреса) Тогда
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Муниципальный", "ИСТИНА");
	Иначе
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Муниципальный", "ЛОЖЬ");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "МуниципальныйРодительскийИдентификатор", "РодительскийИдентификатор");
	КонецЕсли;

	Возврат ТекстЗапроса;

КонецФункции

Функция КаскадныйСписокАвтоподбораНаселенногоПункта(ТипАдреса)

	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	Приоритеты.Уровень КАК Уровень,
	|	Приоритеты.Порядок КАК Порядок
	|ПОМЕСТИТЬ Приоритеты
	|ИЗ
	|	&Приоритеты КАК Приоритеты
	|ИНДЕКСИРОВАТЬ ПО
	|	Уровень,
	|	Порядок
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ ПЕРВЫЕ 10
	|	Приоритеты.Порядок КАК Порядок,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
	|	АдресныеОбъекты.Наименование КАК Наименование,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
	|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс
	|ПОМЕСТИТЬ АдресныйОбъект
	|ИЗ
	|	Приоритеты КАК Приоритеты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (Приоритеты.Уровень = АдресныеОбъекты.Уровень)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (АдресныеОбъекты.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор)
	|ГДЕ
	|	АдресныеОбъекты.Уровень < 8
	|	И (АдресныеОбъекты.Наименование ПОДОБНО &НачалоФразы СПЕЦСИМВОЛ ""~""
	|			ИЛИ АдресныеОбъекты.Наименование ПОДОБНО &НачалоФразыСПробелом СПЕЦСИМВОЛ ""~"")
	|
	|УПОРЯДОЧИТЬ ПО
	|	Порядок
	|" + ОбщегоНазначения.РазделительПакетаЗапросов();

	ТекстЗапросаМуниципальный = "
	|ВЫБРАТЬ ПЕРВЫЕ 10
	|	АдресныйОбъект.Наименование КАК Наименование0,
	|	АдресныйОбъект.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныйОбъект.Уровень КАК Уровень0,
	|	АдресныйОбъект.Идентификатор КАК Идентификатор0,
	|	АдресныйОбъект.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	АдресныйОбъект.КодСубъектаРФ КАК КодСубъектаРФ,
	|	АдресныйОбъект1.Наименование КАК Наименование1,
	|	АдресныйОбъект1.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныйОбъект1.Уровень КАК Уровень1,
	|	АдресныйОбъект1.Идентификатор КАК Идентификатор1,
	|	АдресныйОбъект2.Наименование КАК Наименование2,
	|	АдресныйОбъект2.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныйОбъект2.Уровень КАК Уровень2,
	|	АдресныйОбъект2.Идентификатор КАК Идентификатор2,
	|	АдресныйОбъект3.Наименование КАК Наименование3,
	|	АдресныйОбъект3.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныйОбъект3.Уровень КАК Уровень3,
	|	АдресныйОбъект3.Идентификатор КАК Идентификатор3,
	|	АдресныйОбъект4.Наименование КАК Наименование4,
	|	АдресныйОбъект4.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныйОбъект4.Уровень КАК Уровень4,
	|	АдресныйОбъект4.Идентификатор КАК Идентификатор4,
	|	АдресныйОбъект5.Наименование КАК Наименование5,
	|	АдресныйОбъект5.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныйОбъект5.Уровень КАК Уровень5,
	|	АдресныйОбъект5.Идентификатор КАК Идентификатор5,
	|	ИСТИНА КАК Муниципальный,
	|	АдресныйОбъект.Порядок КАК Порядок
	|ИЗ
	|	АдресныйОбъект КАК АдресныйОбъект
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК Иерархия1
	|		ПО АдресныйОбъект.Идентификатор = Иерархия1.Идентификатор
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК Иерархия2
	|		ПО (Иерархия1.РодительскийИдентификатор = Иерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК Иерархия3
	|		ПО (Иерархия2.РодительскийИдентификатор = Иерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК Иерархия4
	|		ПО (Иерархия3.РодительскийИдентификатор = Иерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК Иерархия5
	|		ПО (Иерархия4.РодительскийИдентификатор = Иерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект1
	|		ПО (Иерархия1.РодительскийИдентификатор = АдресныйОбъект1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект2
	|		ПО (Иерархия2.РодительскийИдентификатор = АдресныйОбъект2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект3
	|		ПО (Иерархия3.РодительскийИдентификатор = АдресныйОбъект3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект4
	|		ПО (Иерархия4.РодительскийИдентификатор = АдресныйОбъект4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект5
	|		ПО (Иерархия5.РодительскийИдентификатор = АдресныйОбъект5.Идентификатор)";

	ТекстЗапросаАдминистративный = "
	|ВЫБРАТЬ ПЕРВЫЕ 10
	|	АдресныйОбъект.Наименование КАК Наименование0,
	|	АдресныйОбъект.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныйОбъект.Уровень КАК Уровень0,
	|	АдресныйОбъект.Идентификатор КАК Идентификатор0,
	|	АдресныйОбъект.ПочтовыйИндекс,
	|	АдресныйОбъект.КодСубъектаРФ КАК КодСубъектаРФ,
	|	АдресныйОбъект1.Наименование КАК Наименование1,
	|	АдресныйОбъект1.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныйОбъект1.Уровень КАК Уровень1,
	|	АдресныйОбъект1.Идентификатор КАК Идентификатор1,
	|	АдресныйОбъект2.Наименование КАК Наименование2,
	|	АдресныйОбъект2.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныйОбъект2.Уровень КАК Уровень2,
	|	АдресныйОбъект2.Идентификатор КАК Идентификатор2,
	|	АдресныйОбъект3.Наименование КАК Наименование3,
	|	АдресныйОбъект3.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныйОбъект3.Уровень КАК Уровень3,
	|	АдресныйОбъект3.Идентификатор КАК Идентификатор3,
	|	АдресныйОбъект4.Наименование КАК Наименование4,
	|	АдресныйОбъект4.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныйОбъект4.Уровень КАК Уровень4,
	|	АдресныйОбъект4.Идентификатор КАК Идентификатор4,
	|	АдресныйОбъект5.Наименование КАК Наименование5,
	|	АдресныйОбъект5.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныйОбъект5.Уровень КАК Уровень5,
	|	АдресныйОбъект5.Идентификатор КАК Идентификатор5,
	|	ЛОЖЬ КАК Муниципальный,
	|	АдресныйОбъект.Порядок
	|ИЗ
	|	АдресныйОбъект КАК АдресныйОбъект
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК Иерархия1
	|		ПО АдресныйОбъект.Идентификатор = Иерархия1.Идентификатор
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК Иерархия2
	|		ПО (Иерархия1.РодительскийИдентификатор = Иерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК Иерархия3
	|		ПО (Иерархия2.РодительскийИдентификатор = Иерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК Иерархия4
	|		ПО (Иерархия3.РодительскийИдентификатор = Иерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК Иерархия5
	|		ПО (Иерархия4.РодительскийИдентификатор = Иерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект1
	|		ПО (Иерархия1.РодительскийИдентификатор = АдресныйОбъект1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект2
	|		ПО (Иерархия2.РодительскийИдентификатор = АдресныйОбъект2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект3
	|		ПО (Иерархия3.РодительскийИдентификатор = АдресныйОбъект3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект4
	|		ПО (Иерархия4.РодительскийИдентификатор = АдресныйОбъект4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныйОбъект5
	|		ПО (Иерархия5.РодительскийИдентификатор = АдресныйОбъект5.Идентификатор)";

	Если ЭтоАдминистративноТерриториальныйАдрес(ТипАдреса) Тогда
		ТекстЗапроса = ТекстЗапроса + ТекстЗапросаАдминистративный;
	ИначеЕсли ЭтоМуниципальныйАдрес(ТипАдреса) Тогда
		ТекстЗапроса =  ТекстЗапроса + ТекстЗапросаМуниципальный;
	Иначе
		ТекстЗапроса = ТекстЗапроса + ТекстЗапросаАдминистративный + "
																	 |
																	 |ОБЪЕДИНИТЬ ВСЕ
																	 |" + ТекстЗапросаМуниципальный;

	КонецЕсли;

	ТекстЗапроса = ТекстЗапроса + "
								  |УПОРЯДОЧИТЬ ПО
								  |	Порядок";

	Возврат ТекстЗапроса;

КонецФункции

// Заполнение адреса по индексу из загруженных данных.
// 
Процедура ЗаполнитьАдресаПоПочтовомуИндексуИзЗагруженныхДанных(Результат, Знач ПочтовыйИндекс, ДополнительныеПараметры)
	
	Если ЗначениеЗаполнено(ДополнительныеПараметры.ТипАдреса) Тогда
		ВключатьМуниципальныеАдреса                  = ЭтоМуниципальныйАдрес(ДополнительныеПараметры.ТипАдреса);
		ВключатьАдминистративноТерриториальныеАдреса = ЭтоАдминистративноТерриториальныйАдрес(
			ДополнительныеПараметры.ТипАдреса);
		Если Не ВключатьАдминистративноТерриториальныеАдреса И Не ВключатьМуниципальныеАдреса Тогда
			Результат.Отказ = Истина;
			Возврат;
		КонецЕсли;
	Иначе
		ВключатьМуниципальныеАдреса                  = Истина;
		ВключатьАдминистративноТерриториальныеАдреса = Истина;
	КонецЕсли;

	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ДомаЗданияСтроения.АдресныйОбъект КАК Идентификатор, 
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК МуниципальнаяИерархияРодительскийИдентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК АдминистративнаяИерархияРодительскийИдентификатор
	|ПОМЕСТИТЬ ИдентификаторыАдресныхОбъектов
	|ИЗ
	|	РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДомаЗданияСтроения КАК ДомаЗданияСтроения
	|		ПО (ДомаЗданияСтроения.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (ДомаЗданияСтроения.АдресныйОбъект = МуниципальнаяИерархия.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (ДомаЗданияСтроения.АдресныйОбъект =АдминистративнаяИерархия.Идентификатор)
	|
	|
	|ГДЕ
	|	ДополнительныеСведения.ПочтовыйИндекс = &ПочтовыйИндекс
	|	И НЕ ДомаЗданияСтроения.АдресныйОбъект ЕСТЬ NULL
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЗемельныеУчастки.АдресныйОбъект КАК Идентификатор, 
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК МуниципальнаяИерархияРодительскийИдентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК АдминистративнаяИерархияРодительскийИдентификатор
	|ИЗ
	|	РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗемельныеУчастки КАК ЗемельныеУчастки
	|		ПО (ЗемельныеУчастки.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (ЗемельныеУчастки.АдресныйОбъект = МуниципальнаяИерархия.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (ЗемельныеУчастки.АдресныйОбъект =АдминистративнаяИерархия.Идентификатор)
	|	
	|ГДЕ
	|	ДополнительныеСведения.ПочтовыйИндекс = &ПочтовыйИндекс
	|	И НЕ ЗемельныеУчастки.АдресныйОбъект ЕСТЬ NULL
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	АдресныеОбъекты.Идентификатор,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК МуниципальнаяИерархияРодительскийИдентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК АдминистративнаяИерархияРодительскийИдентификатор
	|
	|
	|ИЗ
	|	РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.ДополнительныеАдресныеСведения = ДополнительныеСведения.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (АдресныеОбъекты.Идентификатор = МуниципальнаяИерархия.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдресныеОбъекты.Идентификатор =АдминистративнаяИерархия.Идентификатор)
	|
	|ГДЕ
	|	ДополнительныеСведения.ПочтовыйИндекс = &ПочтовыйИндекс
	|	И НЕ АдресныеОбъекты.Идентификатор ЕСТЬ NULL
	|" + ОбщегоНазначения.РазделительПакетаЗапросов();
	
	Если ВключатьМуниципальныеАдреса Тогда 
	
		ТекстЗапроса = ТекстЗапроса + 
		"ВЫБРАТЬ ПЕРВЫЕ 500
		|	ИСТИНА КАК Муниципальный,
		|	АдресныеОбъекты0.Идентификатор КАК Идентификатор,
		|	АдресныеОбъекты0.КодСубъектаРФ КАК КодСубъектаРФ,
		|	АдресныеОбъекты0.Наименование КАК Наименование0,
		|	АдресныеОбъекты0.ТипОбъекта КАК ТипОбъекта0,
		|	АдресныеОбъекты0.Уровень КАК Уровень0,
		|	АдресныеОбъекты1.Наименование КАК Наименование1,
		|	АдресныеОбъекты1.ТипОбъекта КАК ТипОбъекта1,
		|	АдресныеОбъекты1.Уровень КАК Уровень1,
		|	АдресныеОбъекты2.Наименование КАК Наименование2,
		|	АдресныеОбъекты2.ТипОбъекта КАК ТипОбъекта2,
		|	АдресныеОбъекты2.Уровень КАК Уровень2,
		|	АдресныеОбъекты3.Наименование КАК Наименование3,
		|	АдресныеОбъекты3.ТипОбъекта КАК ТипОбъекта3,
		|	АдресныеОбъекты3.Уровень КАК Уровень3,
		|	АдресныеОбъекты4.Наименование КАК Наименование4,
		|	АдресныеОбъекты4.ТипОбъекта КАК ТипОбъекта4,
		|	АдресныеОбъекты4.Уровень КАК Уровень4,
		|	АдресныеОбъекты5.Наименование КАК Наименование5,
		|	АдресныеОбъекты5.ТипОбъекта КАК ТипОбъекта5,
		|	АдресныеОбъекты5.Уровень КАК Уровень5
		|ИЗ
		|	ИдентификаторыАдресныхОбъектов КАК ИдентификаторыАдресныхОбъектов
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия1
		|		ПО (ИдентификаторыАдресныхОбъектов.МуниципальнаяИерархияРодительскийИдентификатор = МуниципальнаяИерархия1.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия2
		|		ПО (МуниципальнаяИерархия1.РодительскийИдентификатор = МуниципальнаяИерархия2.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия3
		|		ПО (МуниципальнаяИерархия2.РодительскийИдентификатор = МуниципальнаяИерархия3.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия4
		|		ПО (МуниципальнаяИерархия3.РодительскийИдентификатор = МуниципальнаяИерархия4.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия5
		|		ПО (МуниципальнаяИерархия4.РодительскийИдентификатор = МуниципальнаяИерархия5.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты0
		|		ПО (АдресныеОбъекты0.Идентификатор = ИдентификаторыАдресныхОбъектов.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты1
		|		ПО (АдресныеОбъекты1.Идентификатор = МуниципальнаяИерархия1.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты2
		|		ПО (АдресныеОбъекты2.Идентификатор = МуниципальнаяИерархия2.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты3
		|		ПО (АдресныеОбъекты3.Идентификатор = МуниципальнаяИерархия3.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты4
		|		ПО (АдресныеОбъекты4.Идентификатор = МуниципальнаяИерархия4.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты5
		|		ПО (АдресныеОбъекты5.Идентификатор = МуниципальнаяИерархия5.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
		|		ПО (ДополнительныеСведения.Идентификатор = АдресныеОбъекты0.ДополнительныеАдресныеСведения)";
		
	КонецЕсли;
	
	Если ВключатьАдминистративноТерриториальныеАдреса Тогда
		
		Если ВключатьМуниципальныеАдреса Тогда
		
			ТекстЗапроса = ТекстЗапроса + "
										  |ОБЪЕДИНИТЬ ВСЕ
										  |";
		
		КонецЕсли;
		
		ТекстЗапроса = ТекстЗапроса + 
		"ВЫБРАТЬ ПЕРВЫЕ 500
		|	ЛОЖЬ КАК Муниципальный,
		|	АдресныеОбъекты0.Идентификатор КАК Идентификатор,
		|	АдресныеОбъекты0.КодСубъектаРФ КАК КодСубъектаРФ,
		|	АдресныеОбъекты0.Наименование КАК Наименование0,
		|	АдресныеОбъекты0.ТипОбъекта КАК ТипОбъекта0,
		|	АдресныеОбъекты0.Уровень КАК Уровень0,
		|	АдресныеОбъекты1.Наименование КАК Наименование1,
		|	АдресныеОбъекты1.ТипОбъекта КАК ТипОбъекта1,
		|	АдресныеОбъекты1.Уровень КАК Уровень1,
		|	АдресныеОбъекты2.Наименование КАК Наименование2,
		|	АдресныеОбъекты2.ТипОбъекта КАК ТипОбъекта2,
		|	АдресныеОбъекты2.Уровень КАК Уровень2,
		|	АдресныеОбъекты3.Наименование КАК Наименование3,
		|	АдресныеОбъекты3.ТипОбъекта КАК ТипОбъекта3,
		|	АдресныеОбъекты3.Уровень КАК Уровень3,
		|	АдресныеОбъекты4.Наименование КАК Наименование4,
		|	АдресныеОбъекты4.ТипОбъекта КАК ТипОбъекта4,
		|	АдресныеОбъекты4.Уровень КАК Уровень4,
		|	АдресныеОбъекты5.Наименование КАК Наименование5,
		|	АдресныеОбъекты5.ТипОбъекта КАК ТипОбъекта5,
		|	АдресныеОбъекты5.Уровень КАК Уровень5
		|ИЗ
		|	 ИдентификаторыАдресныхОбъектов КАК ИдентификаторыАдресныхОбъектов
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия1
		|		ПО ( ИдентификаторыАдресныхОбъектов.АдминистративнаяИерархияРодительскийИдентификатор = АдминистративнаяИерархия1.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия2
		|		ПО (АдминистративнаяИерархия1.РодительскийИдентификатор = АдминистративнаяИерархия2.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия3
		|		ПО (АдминистративнаяИерархия2.РодительскийИдентификатор = АдминистративнаяИерархия3.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия4
		|		ПО (АдминистративнаяИерархия3.РодительскийИдентификатор = АдминистративнаяИерархия4.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия5
		|		ПО (АдминистративнаяИерархия4.РодительскийИдентификатор = АдминистративнаяИерархия5.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты0
		|		ПО (АдресныеОбъекты0.Идентификатор =  ИдентификаторыАдресныхОбъектов.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты1
		|		ПО (АдресныеОбъекты1.Идентификатор = АдминистративнаяИерархия1.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты2
		|		ПО (АдресныеОбъекты2.Идентификатор = АдминистративнаяИерархия2.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты3
		|		ПО (АдресныеОбъекты3.Идентификатор = АдминистративнаяИерархия3.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты4
		|		ПО (АдресныеОбъекты4.Идентификатор = АдминистративнаяИерархия4.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты5
		|		ПО (АдресныеОбъекты5.Идентификатор = АдминистративнаяИерархия5.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
		|		ПО (ДополнительныеСведения.Идентификатор = АдресныеОбъекты0.ДополнительныеАдресныеСведения)";
	
	КонецЕсли;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("ПочтовыйИндекс", ПочтовыйИндекс);
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();
	
	КэшПредставлений = Новый Соответствие;
	Для Каждого  ДанныеАдреса Из РезультатЗапроса Цикл
		
		НаборНаименований = Новый Массив;
		Для Позиция = 0 По 5 Цикл
			
			Если ПустаяСтрока(ДанныеАдреса["Наименование" + Позиция]) Тогда
				Прервать;
			КонецЕсли;
			
			ЭтоРегион = ЭтоУровеньРегиона(ДанныеАдреса["Уровень" + Позиция]);
			Если ЭтоРегион Тогда
				Наименование = ПолноеНаименованиеРегионаПоКоду(ДанныеАдреса["КодСубъектаРФ"]);
			Иначе
				Наименование = СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса["Наименование" + Позиция],
					ДанныеАдреса["ТипОбъекта" + Позиция]);
			КонецЕсли;
			НаборНаименований.Добавить(Наименование);
			
		КонецЦикла;
		
		Представление = СтрСоединить(НаборНаименований, ", ");
		
		Если КэшПредставлений.Получить(Представление) = Неопределено Тогда
			КэшПредставлений.Вставить(Представление, Истина);
			
			НоваяСтрока = Результат.Данные.Добавить();
			НоваяСтрока.Представление     = Представление;
			НоваяСтрока.ЗагруженныеДанные = Истина;
			НоваяСтрока.Муниципальный     = ДанныеАдреса.Муниципальный;
			НоваяСтрока.Идентификатор     = ДанныеАдреса.Идентификатор;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Результат.Данные.Сортировать("Представление,Муниципальный");

КонецПроцедуры

// Заполнение данных для выбора адреса из загруженных данных.
// 
Процедура ЗаполнитьАдресаДляВыбораПоЗагруженнымДанным(Результат, Родитель, Уровень, ТипАдреса, ДополнительныеПараметры)
	
	Запрос = Новый Запрос;
	
	Если ЭтоУровеньРегиона(Уровень) Тогда
		
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	ЕСТЬNULL(ВЫРАЗИТЬ(СлужебныеАдресныеСведения.Идентификатор КАК ЧИСЛО(2, 0)), АдресныеОбъекты.КодСубъектаРФ) КАК КодСубъектаРФ,
		|	ЕСТЬNULL(СлужебныеАдресныеСведения.Значение, АдресныеОбъекты.Наименование + "" "" + АдресныеОбъекты.ТипОбъекта) КАК Представление,
		|	АдресныеОбъекты.Наименование КАК Наименование,
		|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
		|	АдресныеОбъекты.Уровень КАК Уровень,
		|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
		|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныйИдентификатор,
		|	ИСТИНА КАК Муниципальный,
		|	ИСТИНА КАК РегионЗагружен,
		|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс
		|ИЗ
		|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СлужебныеАдресныеСведения КАК СлужебныеАдресныеСведения
		|		ПО ((ВЫРАЗИТЬ(СлужебныеАдресныеСведения.Идентификатор КАК ЧИСЛО(2, 0))) = АдресныеОбъекты.КодСубъектаРФ)
		|			И (СлужебныеАдресныеСведения.Тип = &Тип)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
		|		ПО ДополнительныеСведения.Идентификатор = АдресныеОбъекты.ДополнительныеАдресныеСведения
		|
		|ГДЕ
		|	АдресныеОбъекты.Уровень = 1
		|	И &ОтборПоСтроке
		|
		|УПОРЯДОЧИТЬ ПО
		|	КодСубъектаРФ";
		
		Запрос.УстановитьПараметр("Тип", "СубъектыРФ");
		
	Иначе
		
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	АдресныеОбъекты.ТипОбъекта + "" "" + АдресныеОбъекты.Наименование КАК Представление,
		|	АдресныеОбъекты.Наименование КАК Наименование,
		|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
		|	АдресныеОбъекты.Уровень КАК Уровень,
		|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
		|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
		|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныйИдентификатор,
		|	ИСТИНА КАК РегионЗагружен,
		|	ИСТИНА КАК Муниципальный,
		|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс
		|ИЗ
		|	РегистрСведений.МуниципальнаяИерархия КАК ИерархияАдресов
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
		|		ПО (ИерархияАдресов.Идентификатор = АдресныеОбъекты.Идентификатор)
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
		|		ПО ДополнительныеСведения.Идентификатор = АдресныеОбъекты.ДополнительныеАдресныеСведения
		|ГДЕ
		|	ИерархияАдресов.РодительскийИдентификатор = &Идентификатор
		|	И АдресныеОбъекты.Уровень = &Уровень
		|	И &ОтборПоСтроке
		|
		|УПОРЯДОЧИТЬ ПО
		|	Наименование,
		|	ТипОбъекта";

		Запрос.УстановитьПараметр("Идентификатор", Родитель);
		Запрос.УстановитьПараметр("Уровень", Уровень);

	КонецЕсли;

	ИскатьПоАдминистративнымДанным = 
		(АдресныйКлассификаторПовтИсп.ИдентификаторыГородовФедеральногоЗначения().Получить(Родитель) = Истина 
		И  ЭтоУровеньУлицы(Уровень))
		Или ЭтоАдминистративноТерриториальныйАдрес(ТипАдреса);
		
	Если ИскатьПоАдминистративнымДанным Тогда
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.МуниципальнаяИерархия",
			"РегистрСведений.АдминистративнаяИерархия");
	КонецЕсли;

	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") И ДополнительныеПараметры.Свойство("СтрокаПоиска")
		И ЗначениеЗаполнено(ДополнительныеПараметры.СтрокаПоиска) Тогда

		Если ЭтоУровеньУлицы(Уровень) Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоСтроке",
				" АдресныеОбъекты.Наименование ПОДОБНО ""%"" + &СтрокаПоиска + ""%"" СПЕЦСИМВОЛ ""~""");
		Иначе
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоСтроке", " (АдресныеОбъекты.Наименование ПОДОБНО &СтрокаПоиска + ""%"" СПЕЦСИМВОЛ ""~""
															| ИЛИ АдресныеОбъекты.Наименование ПОДОБНО "" "" + &СтрокаПоиска + ""%"" СПЕЦСИМВОЛ ""~"")");
		КонецЕсли;
		Запрос.УстановитьПараметр("СтрокаПоиска", 
			ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ДополнительныеПараметры.СтрокаПоиска));

	Иначе
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоСтроке", "ИСТИНА");
	КонецЕсли;

	Если ЭтоМуниципальныйАдрес(ТипАдреса) И Уровень
		= АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().city Тогда

		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "АдресныеОбъекты.Уровень = &Уровень",
			"(АдресныеОбъекты.Уровень = &Уровень ИЛИ АдресныеОбъекты.Уровень = &УровеньРайона)");
		Запрос.УстановитьПараметр("УровеньРайона",
			АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().district);

	КонецЕсли;

	Запрос.Текст = ТекстЗапроса;
	РезультатЗапроса = Запрос.Выполнить();

	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;

	Данные = Результат.Данные;
	Для Каждого Строка Из РезультатЗапроса.Выгрузить() Цикл

		Если Не ЭтоУровеньРегиона(Уровень) И ЗначениеЗаполнено(Строка.ПочтовыйИндекс) Тогда
			Строка.Представление = Строка.Представление + " (" + Формат(Строка.ПочтовыйИндекс, "ЧГ=0") + ")";
		КонецЕсли;

		СтрокаДанных = Данные.Добавить();
		ЗаполнитьЗначенияСвойств(СтрокаДанных, Строка);

	КонецЦикла;

КонецПроцедуры

// Конструктор таблицы - результата выбора.
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Неактуален - Булево
//   * Идентификатор - УникальныйИдентификатор
//   * Представление - Строка
//   * РегионЗагружен - Булево
//   * ЭтоМуниципальный - Булево
//   * Уровень - Число
//   * Наименование - Строка
//   * ТипОбъекта - Строка
// 
Функция ТаблицаДанныхДляИнтерактивногоВыбора()

	ТипБулево = Новый ОписаниеТипов("Булево");
	Данные    = Новый ТаблицаЗначений;
	Колонки   = Данные.Колонки;

	Колонки.Добавить("Неактуален", ТипБулево);
	Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("РегионЗагружен", ТипБулево);
	Колонки.Добавить("ЭтоМуниципальный", ТипБулево);
	Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число"));
	Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ТипОбъекта", Новый ОписаниеТипов("Строка"));

	Данные.Индексы.Добавить("Идентификатор");
	Данные.Индексы.Добавить("Представление");

	Возврат Данные
КонецФункции

Процедура ОбновитьАдресныеСокращения(Знач КаталогФайлов)

	АдресныеСокращения = АдресныеСокращенияИзФайла(КаталогФайлов);
	Набор = РегистрыСведений.УровниСокращенийАдресныхСведений.СоздатьНаборЗаписей();
	Набор.Загрузить(АдресныеСокращения.Сведения);
	ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор); // Отключаем всю бизнес-логику для ускорения операции.

КонецПроцедуры

Процедура ОповеститьОПрогрессе(Знач НаименованиеРегиона, Знач СубъектРФ, Знач ОсталосьДляЗагрузки)

	Если ОсталосьДляЗагрузки > 0 Тогда
		ШаблонСообщения = НСтр("ru = 'Загрузка региона ""%1 - %2""... (осталось %3)'");
		ТекстОсталосьЗагрузить = Формат(ОсталосьДляЗагрузки, "ЧН=");
	Иначе
		ШаблонСообщения = НСтр("ru = 'Загрузка региона ""%1 - %2""'") + "...";
		ТекстОсталосьЗагрузить = "";
	КонецЕсли;

	ИнформацияОЗагрузке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, СубъектРФ,
		НаименованиеРегиона, ТекстОсталосьЗагрузить);

	ДлительныеОперации.СообщитьПрогресс( , ИнформацияОЗагрузке);

КонецПроцедуры

Процедура ОбновитьСлужебныеАдресныеСведения(СлужебныеАдресныеСведения)

	Набор = РегистрыСведений.СлужебныеАдресныеСведения.СоздатьНаборЗаписей();
	Набор.Очистить();
	Набор.Загрузить(СлужебныеАдресныеСведения.Сведения);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Функция ИзвлечьФайлыВКаталог(ОписаниеФайлов, Знач КаталогФайлов = Неопределено) Экспорт
	
	// Извлекаем файлы
	Если КаталогФайлов = Неопределено Тогда
		КаталогФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ПолучитьИмяВременногоФайла());
		СоздатьКаталог(КаталогФайлов);
	КонецЕсли;

	Если ТипЗнч(ОписаниеФайлов) <> Тип("Массив") Тогда
		// Если ОписаниеФайлов не массив, то данные передаются через константу, после извлечения очищаем передаваемые данные.
		ПараметрыАдресногоКлассификатора = Константы.ПараметрыАдресногоКлассификатора.Получить().Получить();
		ОписаниеФайлов = ПараметрыАдресногоКлассификатора.ОписаниеФайлов;
		ПараметрыАдресногоКлассификатора.Удалить("ОписаниеФайлов");
		ХранилищеПараметров = Новый ХранилищеЗначения(ПараметрыАдресногоКлассификатора);
		Константы.ПараметрыАдресногоКлассификатора.Установить(ХранилищеПараметров);
	КонецЕсли;

	Для Каждого ОписаниеФайла Из ОписаниеФайлов Цикл
		Файл = Новый Файл(ОписаниеФайла.Имя);
		ПолноеИмяФайла = КаталогФайлов + ВРег(Файл.Имя);

		Данные = ОписаниеФайла.Хранение;

		Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
			Данные.Записать(ПолноеИмяФайла);

		ИначеЕсли ЭтоАдресВременногоХранилища(Данные) Тогда
			Данные = ПолучитьИзВременногоХранилища(Данные); // ДвоичныеДанные
			Данные.Записать(ПолноеИмяФайла);

		Иначе
			ПолноеИмяФайла = Данные;
		КонецЕсли;

		ФайлАрхива = Новый Файл(ПолноеИмяФайла);

		Если ФайлАрхива.Существует() И ВРег(Прав(ПолноеИмяФайла, 4)) = ".ZIP" Тогда

			Архив = Новый ЧтениеZipФайла(ПолноеИмяФайла);

			ЕстьФайлВерсииСМуниципальнымиДанными    = Ложь;

			Для Каждого ЭлементАрхива Из Архив.Элементы Цикл

				Если СтрНайти(ЭлементАрхива.Имя, "ADDRMUN.FI") > 0 Тогда
					ЕстьФайлВерсииСМуниципальнымиДанными = Истина;
					Прервать;
				КонецЕсли;

			КонецЦикла;

			Если Не ЕстьФайлВерсииСМуниципальнымиДанными Тогда

				Архив.Закрыть();

				ТекстПричины = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Допускается загрузка адресных сведений только в формате Государственного адресного реестра (ГАР).
					|см. %1'"), "https://its.1c.ru/download/gar");
				
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось загрузить адресные сведения из файла: %1
						|по причине: %2
						|См. https://its.1c.ru/download/gar'"),
					ПолноеИмяФайла, ТекстПричины));
				ВызватьИсключение ТекстПричины;

			КонецЕсли;

			Архив.ИзвлечьВсе(КаталогФайлов + ФайлАрхива.ИмяБезРасширения,
				РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
			Архив.Закрыть();

			УдалитьФайлы(ПолноеИмяФайла);

		КонецЕсли;

	КонецЦикла;

	СписокИзвлеченныхФайлов(КаталогФайлов);

	Возврат КаталогФайлов;

КонецФункции

Процедура СписокИзвлеченныхФайлов(КаталогФайлов)

	НайденныеФайлы = НайтиФайлы(КаталогФайлов, ПолучитьМаскуВсеФайлы(), Истина);
	СписокФайлов = Новый Массив;
	Для Каждого НайденныеФайл Из НайденныеФайлы Цикл
		Если НайденныеФайл.ЭтоФайл() Тогда
			СписокФайлов.Добавить(НайденныеФайл.Имя);
		КонецЕсли;
	КонецЦикла;

	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Примечание, , ,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
		"ru = 'Список извлеченных файлов адресных сведений региона: %1'"), СтрСоединить(СписокФайлов, ",")));
КонецПроцедуры

Функция НоваяТаблицаАдресовСРазбивкойНаПоля()

	Строка250 = ОбщегоНазначения.ОписаниеТипаСтрока(250);
	Строка20  = ОбщегоНазначения.ОписаниеТипаСтрока(20);
	АдресаПоПолям = Новый ТаблицаЗначений;
	АдресаПоПолям.Колонки.Добавить("Ключ", ОбщегоНазначения.ОписаниеТипаЧисло(3));
	АдресаПоПолям.Колонки.Добавить("ЭтоМуниципальныйАдрес", Новый ОписаниеТипов("Булево"));
	АдресаПоПолям.Колонки.Добавить("Наименование0", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта0", Строка20);
	АдресаПоПолям.Колонки.Добавить("Наименование1", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта1", Строка20);
	АдресаПоПолям.Колонки.Добавить("Наименование2", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта2", Строка20);
	АдресаПоПолям.Колонки.Добавить("Наименование3", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта3", Строка20);
	АдресаПоПолям.Колонки.Добавить("Наименование4", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта4", Строка20);
	АдресаПоПолям.Колонки.Добавить("Наименование5", Строка250);
	АдресаПоПолям.Колонки.Добавить("ТипОбъекта5", Строка20);

	Возврат АдресаПоПолям;

КонецФункции

Функция ПервичнаяПроверкаАдресов(Знач Адреса)

	Сведения = Новый Структура;
	Сведения.Вставить("Адреса", Новый Соответствие);
	Сведения.Вставить("КодыРегионов", Новый Массив);

	Для Каждого КлючЗначение Из Адреса Цикл

		Результат = РезультатПроверкиАдреса();
		Сведения.Адреса.Вставить(КлючЗначение.Ключ, Результат);

		Адрес = КлючЗначение.Значение;
		Если ЭтоКонтактнаяИнформацияВXML(Адрес) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ", НСтр(
				"ru = 'Адрес не может быть проверен, так как он в старом формате'"));
			Результат.АдресПроверен   = Истина;
			Результат.АдресКорректный = Ложь;
			Продолжить;

		КонецЕсли;

		Результат = Сведения.Адреса[КлючЗначение.Ключ]; // см. РезультатПроверкиАдреса
		Если СтрСравнить("ВСвободнойФорме", Адрес.AddressType) = 0 Тогда
			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ", НСтр(
				"ru = 'Адрес не может быть проверен, так как он введен в свободной форме'"));
			Результат.АдресПроверен   = Истина;
			Результат.АдресКорректный = Истина;
			Продолжить;
		КонецЕсли;

		Если СтрСравнить(Адрес.country, ОсновнаяСтрана()) <> 0 Тогда
			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ", НСтр(
				"ru = 'Адрес не может быть проверен, так как он иностранный'"));
			Результат.АдресПроверен   = Истина;
			Результат.АдресКорректный = Истина;
			Продолжить;
		КонецЕсли;
		
		// Субъект должен быть всегда
		Если ПустаяСтрока(Адрес.Area) Тогда
			// Нет субъекта
			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ", НСтр(
				"ru = 'Не указан регион адреса'"));
			Результат.АдресПроверен   = Истина;
			Продолжить;
		КонецЕсли;
		
		АдресныеСведенияРегиона = СведенияОРегионе(Адрес.area, Адрес.areaType);
		
		Если АдресныеСведенияРегиона.Устарел Тогда
			//@skip-check query-in-loop - редкий штучный запрос, только для актуализации данных региона.
			АктуализироватьДанныеОРегионе(Адрес, АдресныеСведенияРегиона.КодСубъектаРФ, Результат); // Вызывается, только если адрес устарел.
		ИначеЕсли Не АдресныеСведенияРегиона.Загружен Тогда
			
			НаименованиеРегиона = ?(ЗначениеЗаполнено(АдресныеСведенияРегиона.ПолноеНаименование), 
				АдресныеСведенияРегиона.ПолноеНаименование,
				СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.area, Адрес.areaType, Истина));
			
			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ",
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
				"ru = 'Отсутствуют адресные сведения по региону: %1'"), НаименованиеРегиона));
			Результат.АдресПроверен   = Ложь;
			Результат.АдресКорректный = Истина;
			Продолжить;
		Иначе
			Если Сведения.КодыРегионов.Найти(АдресныеСведенияРегиона.КодСубъектаРФ) = Неопределено Тогда
				Сведения.КодыРегионов.Добавить(АдресныеСведенияРегиона.КодСубъектаРФ);
			КонецЕсли;
		КонецЕсли;

	КонецЦикла;

	Возврат Сведения;

КонецФункции

// Возвращаемое значение:
//  Структура:
//    * АдресКорректный - Булево
//    * АдресУстарел - Булево
//    * АдресПроверен - Булево
//    * Варианты - Массив
//    * Ошибки - Массив
//
Функция РезультатПроверкиАдреса() Экспорт

	Результат = Новый Структура;
	Результат.Вставить("Ошибки", Новый Массив);
	Результат.Вставить("Варианты", Новый Массив);
	Результат.Вставить("АдресПроверен", Ложь);
	Результат.Вставить("АдресУстарел", Ложь);
	Результат.Вставить("АдресКорректный", Ложь);
	Возврат Результат;

КонецФункции

Функция ПроверитьАдресаПоЗагруженнымДанным(Адреса, ПроверятьУстареваниеАдресов = Ложь)

	ПодготовленныеДанные = ПервичнаяПроверкаАдресов(Адреса);
	Результаты   = ПодготовленныеДанные.Адреса;
	КодыРегионов = ПодготовленныеДанные.КодыРегионов;

	ДанныеДляПроверкиАдресов = СформироватьДанныеДляПроверкиАдресов(Адреса, Результаты);

	Если ДанныеДляПроверкиАдресов.АдресаПоПолям.Количество() = 0 Тогда
		Возврат Результаты;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапросаПроверкиАдресов();
	Запрос.УстановитьПараметр("АдресаПоПолям", ДанныеДляПроверкиАдресов.АдресаПоПолям);
	Запрос.УстановитьПараметр("КодыРегионов", КодыРегионов);

	РезультатЗапроса       = Запрос.ВыполнитьПакет();
	ВариантыАдресов        = РезультатЗапроса[13];
	ДомаИСведения          = РезультатЗапроса[14];
	Участки                = РезультатЗапроса[15];

	АнализАдресныхОбъектов(Результаты, Адреса, ДанныеДляПроверкиАдресов.ПроверяемыеУровни, ВариантыАдресов,
		ПроверятьУстареваниеАдресов);
	АнализДомовИДополнительныхСведений(Результаты, Адреса, ДомаИСведения, Участки);

	Возврат Результаты;

КонецФункции

// Проверка адрес на соответствие адресного классификатора
//
// Параметры:
//  Адреса - Соответствие из КлючИЗначение:
//   * Ключ - Число - уникальный ключ адреса,
//   * Значение - Строка - строка в формате JSON с адресом.
// 
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - Число - уникальный ключ адреса, 
//   * Значение - Структура:
//     * Ошибки - Массив из Строка - список ошибок 
//     * Варианты - Массив из Строка - варианты нового адреса, если адрес устарел
//     * АдресПроверен - Булево - признак, что адрес был проверен
//     * АдресКорректный - Булево - признак, что адрес корректный
//
Функция ПроверитьАдресаПоКлассификатору(Адреса, ПроверятьУстареваниеАдресов = Ложь)

	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("АнализАдресовПоКлассификатору", "Адреса", Адреса, Тип(
		"Соответствие"));

	Результаты = ПроверитьАдресаПоЗагруженнымДанным(Адреса, ПроверятьУстареваниеАдресов);

	Возврат Результаты;

КонецФункции

Функция ИменаУровнейАдресаПоКоду()

	Уровни = Новый Соответствие;

	Уровни.Вставить(1, "area");
	Уровни.Вставить(2, "district");
	Уровни.Вставить(3, "munDistrict");
	Уровни.Вставить(4, "settlement");
	Уровни.Вставить(5, "city");
	Уровни.Вставить(6, "locality");
	Уровни.Вставить(7, "territory");
	Уровни.Вставить(8, "street");

	Возврат Уровни;

КонецФункции

Функция ИмяУровнейНаселенногоПункта()

	Уровни = Новый Соответствие;

	Уровни.Вставить("district",    Истина);
	Уровни.Вставить("munDistrict", Истина);
	Уровни.Вставить("settlement",  Истина);
	Уровни.Вставить("city",        Истина);
	Уровни.Вставить("locality",    Истина);
	Уровни.Вставить("territory",   Истина);

	Возврат Уровни;

КонецФункции

Функция СформироватьДанныеДляПроверкиАдресов(Знач Адреса, Знач Результаты)

	ПроверяемыеУровни = Новый Соответствие;
	АдресаПоПолям = НоваяТаблицаАдресовСРазбивкойНаПоля();

	Для Каждого КлючЗначение Из Адреса Цикл

		Если Результаты[КлючЗначение.Ключ].АдресПроверен Тогда
			Продолжить;
		КонецЕсли;

		Адрес   = КлючЗначение.Значение;
		НомерПозиции = 0;
		
		// Обратная совместимость
		Адрес.munDistrictType = ИсправлениеСокращений(Адрес.munDistrictType);
		Адрес.munDistrict     = КраткоеНаписаниеМуниципальныхРайонов(Адрес.munDistrict, Адрес.munDistrictType);

		Адрес.settlementType = ИсправлениеСокращений(Адрес.settlementType);
		Адрес.settlement     = КраткоеНаписаниеПоселений(Адрес.settlement, Адрес.settlementType);

		ПроверяемыеУровниАдреса  = Новый Соответствие;
		ИменаУровнейАдреса = ИменаУровнейАдреса(Адрес, Истина, Истина);

		АдресПоПолям = АдресаПоПолям.Добавить();
		АдресПоПолям.ЭтоМуниципальныйАдрес = ЭтоМуниципальныйАдрес(Адрес.addressType);
		АдресПоПолям.Ключ = КлючЗначение.Ключ;

		Для Каждого УровеньАдреса Из ИменаУровнейАдреса Цикл
			Если Адрес.Свойство(УровеньАдреса) И ЗначениеЗаполнено(Адрес[УровеньАдреса]) И НомерПозиции < 6 Тогда

				Наименование = Адрес[УровеньАдреса];
				ТипОбъекта = Адрес[УровеньАдреса + "Type"];
				
				// Обратная совместимость
				Если СтрСравнить(УровеньАдреса, "MunDistrict") = 0 Тогда
					Наименование = КраткоеНаписаниеМуниципальныхРайонов(Наименование, ТипОбъекта);
				КонецЕсли;

				Если СтрСравнить(УровеньАдреса, "Settlement") = 0 Тогда
					Наименование = КраткоеНаписаниеПоселений(Наименование, ТипОбъекта);
				КонецЕсли;

				АдресПоПолям["Наименование" + XMLСтрока(НомерПозиции)] = Наименование;
				АдресПоПолям["ТипОбъекта" + XMLСтрока(НомерПозиции)] = ТипОбъекта;
				ПроверяемыеУровниАдреса.Вставить(УровеньАдреса, НомерПозиции);
				НомерПозиции = НомерПозиции + 1;

			КонецЕсли;
		КонецЦикла;
		ПроверяемыеУровни.Вставить(КлючЗначение.Ключ, ПроверяемыеУровниАдреса);
	КонецЦикла;

	Результат = Новый Структура;
	Результат.Вставить("АдресаПоПолям", АдресаПоПолям);
	Результат.Вставить("ПроверяемыеУровни", ПроверяемыеУровни);

	Возврат Результат;

КонецФункции

Функция ТекстЗапросаПроверкиАдресов()

	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресаПоПолям.ЭтоМуниципальныйАдрес КАК ЭтоМуниципальныйАдрес,
	|	АдресаПоПолям.Наименование0 КАК Наименование0,
	|	АдресаПоПолям.ТипОбъекта0 КАК ТипОбъекта0,
	|	АдресаПоПолям.Наименование1 КАК Наименование1,
	|	АдресаПоПолям.ТипОбъекта1 КАК ТипОбъекта1,
	|	АдресаПоПолям.Наименование2 КАК Наименование2,
	|	АдресаПоПолям.ТипОбъекта2 КАК ТипОбъекта2,
	|	АдресаПоПолям.Наименование3 КАК Наименование3,
	|	АдресаПоПолям.ТипОбъекта3 КАК ТипОбъекта3,
	|	АдресаПоПолям.Наименование4 КАК Наименование4,
	|	АдресаПоПолям.ТипОбъекта4 КАК ТипОбъекта4,
	|	АдресаПоПолям.Наименование5 КАК Наименование5,
	|	АдресаПоПолям.ТипОбъекта5 КАК ТипОбъекта5
	|ПОМЕСТИТЬ АдресаПоПолям
	|ИЗ
	|	&АдресаПоПолям КАК АдресаПоПолям
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	Ключ,
	|	Наименование0,
	|	ТипОбъекта0,
	|	Наименование1,
	|	ТипОбъекта1,
	|	Наименование2,
	|	ТипОбъекта2,
	|	Наименование3,
	|	ТипОбъекта3,
	|	Наименование4,
	|	ТипОбъекта4,
	|	Наименование5,
	|	ТипОбъекта5
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресаПоПолям.ЭтоМуниципальныйАдрес КАК ЭтоМуниципальныйАдрес,
	|	АдресныеОбъекты.Наименование КАК Наименование0,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.Идентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ Регионы
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование0)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта0)
	|			И (АдресныеОбъекты.Уровень = 1)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	Ключ
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование1,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ МуниципальныеАдресныеОбъекты1
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование1)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта1)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Регионы КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|			И (АдресныеОбъектыИдентификаторы.ЭтоМуниципальныйАдрес = ИСТИНА)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (МуниципальнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (МуниципальнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ МуниципальнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование2,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор
	|ПОМЕСТИТЬ МуниципальныеАдресныеОбъекты2
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование2)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта2)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты1 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (МуниципальнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (МуниципальнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ МуниципальнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование3,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор
	|ПОМЕСТИТЬ МуниципальныеАдресныеОбъекты3
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование3)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта3)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты2 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (МуниципальнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (МуниципальнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ МуниципальнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование4,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор
	|ПОМЕСТИТЬ МуниципальныеАдресныеОбъекты4
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование4)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта4)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты3 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (МуниципальнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (МуниципальнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ МуниципальнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование5,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор
	|ПОМЕСТИТЬ МуниципальныеАдресныеОбъекты5
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование5)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта5)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты4 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (МуниципальнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (МуниципальнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ МуниципальнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование1,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдминистративныеАдресныеОбъекты1
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование1)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта1)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Регионы КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|			И (АдресныеОбъектыИдентификаторы.ЭтоМуниципальныйАдрес = ЛОЖЬ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдминистративнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (АдминистративнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ АдминистративнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование2,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдминистративныеАдресныеОбъекты2
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование2)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта2)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты1 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдминистративнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (АдминистративнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ АдминистративнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъектыИдентификаторы.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование3,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдминистративныеАдресныеОбъекты3
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование3)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта3)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты2 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдминистративнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (АдминистративнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ АдминистративнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъектыИдентификаторы.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование4,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдминистративныеАдресныеОбъекты4
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование4)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта4)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты3 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдминистративнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (АдминистративнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ АдминистративнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	АдресныеОбъекты.Наименование КАК Наименование5,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдминистративнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдминистративныеАдресныеОбъекты5
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Наименование = АдресаПоПолям.Наименование5)
	|			И (АдресныеОбъекты.ТипОбъекта = АдресаПоПолям.ТипОбъекта5)
	|			И (АдресныеОбъекты.КодСубъектаРФ В (&КодыРегионов))
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты4 КАК АдресныеОбъектыИдентификаторы
	|		ПО (АдресныеОбъектыИдентификаторы.Ключ = АдресаПоПолям.Ключ)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдминистративнаяИерархия КАК АдминистративнаяИерархия
	|		ПО (АдминистративнаяИерархия.РодительскийИдентификатор = АдресныеОбъектыИдентификаторы.Идентификатор)
	|			И (АдминистративнаяИерархия.Идентификатор = АдресныеОбъекты.Идентификатор)
	|			И (НЕ АдминистративнаяИерархия.Идентификатор ЕСТЬ NULL)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ КАК Ключ,
	|	ЕСТЬNULL(АдресныеОбъектыУровень5.Идентификатор, ЕСТЬNULL(АдресныеОбъектыУровень4.Идентификатор, ЕСТЬNULL(АдресныеОбъектыУровень3.Идентификатор, ЕСТЬNULL(АдресныеОбъектыУровень2.Идентификатор, ЕСТЬNULL(АдресныеОбъектыУровень1.Идентификатор, АдресныеОбъектыУровень0.Идентификатор))))) КАК Идентификатор,
	|	АдресныеОбъектыУровень0.Идентификатор КАК ИдентификаторУровень0,
	|	АдресныеОбъектыУровень1.Идентификатор КАК ИдентификаторУровень1,
	|	АдресныеОбъектыУровень2.Идентификатор КАК ИдентификаторУровень2,
	|	АдресныеОбъектыУровень3.Идентификатор КАК ИдентификаторУровень3,
	|	АдресныеОбъектыУровень4.Идентификатор КАК ИдентификаторУровень4,
	|	АдресныеОбъектыУровень5.Идентификатор КАК ИдентификаторУровень5,
	|	АдресныеОбъектыУровень0.Уровень КАК Уровень0,
	|	АдресныеОбъектыУровень1.Уровень КАК Уровень1,
	|	АдресныеОбъектыУровень2.Уровень КАК Уровень2,
	|	АдресныеОбъектыУровень3.Уровень КАК Уровень3,
	|	АдресныеОбъектыУровень4.Уровень КАК Уровень4,
	|	АдресныеОбъектыУровень5.Уровень КАК Уровень5,
	|	АдресныеОбъектыУровень0.Наименование0 КАК Наименование0,
	|	АдресныеОбъектыУровень0.ТипОбъекта0 КАК ТипОбъекта0,
	|	АдресныеОбъектыУровень1.Наименование1 КАК Наименование1,
	|	АдресныеОбъектыУровень1.ТипОбъекта1 КАК ТипОбъекта1,
	|	АдресныеОбъектыУровень2.Наименование2 КАК Наименование2,
	|	АдресныеОбъектыУровень2.ТипОбъекта2 КАК ТипОбъекта2,
	|	АдресныеОбъектыУровень3.Наименование3 КАК Наименование3,
	|	АдресныеОбъектыУровень3.ТипОбъекта3 КАК ТипОбъекта3,
	|	АдресныеОбъектыУровень4.Наименование4 КАК Наименование4,
	|	АдресныеОбъектыУровень4.ТипОбъекта4 КАК ТипОбъекта4,
	|	АдресныеОбъектыУровень5.Наименование5 КАК Наименование5,
	|	АдресныеОбъектыУровень5.ТипОбъекта5 КАК ТипОбъекта5,
	|	ЕСТЬNULL(АдресныеОбъектыУровень5.ДополнительныеСведения, ЕСТЬNULL(АдресныеОбъектыУровень4.ДополнительныеСведения, ЕСТЬNULL(АдресныеОбъектыУровень3.ДополнительныеСведения, ЕСТЬNULL(АдресныеОбъектыУровень2.ДополнительныеСведения, ЕСТЬNULL(АдресныеОбъектыУровень1.ДополнительныеСведения, АдресныеОбъектыУровень0.ДополнительныеСведения))))) КАК ДополнительныеСведения,
	|	ЕСТЬNULL(АдресныеОбъектыУровень5.Уровень, ЕСТЬNULL(АдресныеОбъектыУровень4.Уровень, ЕСТЬNULL(АдресныеОбъектыУровень3.Уровень, ЕСТЬNULL(АдресныеОбъектыУровень2.Уровень, ЕСТЬNULL(АдресныеОбъектыУровень1.Уровень, АдресныеОбъектыУровень0.Уровень))))) КАК Уровень
	|ПОМЕСТИТЬ АдресныеОбъекты
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ЛЕВОЕ СОЕДИНЕНИЕ Регионы КАК АдресныеОбъектыУровень0
	|		ПО АдресаПоПолям.Ключ = АдресныеОбъектыУровень0.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты1 КАК АдресныеОбъектыУровень1
	|		ПО (АдресныеОбъектыУровень0.Идентификатор = АдресныеОбъектыУровень1.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдресныеОбъектыУровень1.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты2 КАК АдресныеОбъектыУровень2
	|		ПО (АдресныеОбъектыУровень1.Идентификатор = АдресныеОбъектыУровень2.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдресныеОбъектыУровень2.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты3 КАК АдресныеОбъектыУровень3
	|		ПО (АдресныеОбъектыУровень2.Идентификатор = АдресныеОбъектыУровень3.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдресныеОбъектыУровень3.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты4 КАК АдресныеОбъектыУровень4
	|		ПО (АдресныеОбъектыУровень3.Идентификатор = АдресныеОбъектыУровень4.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдресныеОбъектыУровень4.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ МуниципальныеАдресныеОбъекты5 КАК АдресныеОбъектыУровень5
	|		ПО (АдресныеОбъектыУровень4.Идентификатор = АдресныеОбъектыУровень5.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдресныеОбъектыУровень5.Ключ
	|ГДЕ
	|	АдресныеОбъектыУровень0.ЭтоМуниципальныйАдрес = ИСТИНА
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	АдресаПоПолям.Ключ,
	|	ЕСТЬNULL(АдминистративныеАдресныеОбъекты5.Идентификатор, ЕСТЬNULL(АдминистративныеАдресныеОбъекты4.Идентификатор, ЕСТЬNULL(АдминистративныеАдресныеОбъекты3.Идентификатор, ЕСТЬNULL(АдминистративныеАдресныеОбъекты2.Идентификатор, ЕСТЬNULL(АдминистративныеАдресныеОбъекты1.Идентификатор, АдминистративныеАдресныеОбъекты0.Идентификатор))))),
	|	АдминистративныеАдресныеОбъекты0.Идентификатор,
	|	АдминистративныеАдресныеОбъекты1.Идентификатор,
	|	АдминистративныеАдресныеОбъекты2.Идентификатор,
	|	АдминистративныеАдресныеОбъекты3.Идентификатор,
	|	АдминистративныеАдресныеОбъекты4.Идентификатор,
	|	АдминистративныеАдресныеОбъекты5.Идентификатор,
	|	АдминистративныеАдресныеОбъекты0.Уровень,
	|	АдминистративныеАдресныеОбъекты1.Уровень,
	|	АдминистративныеАдресныеОбъекты2.Уровень,
	|	АдминистративныеАдресныеОбъекты3.Уровень,
	|	АдминистративныеАдресныеОбъекты4.Уровень,
	|	АдминистративныеАдресныеОбъекты5.Уровень,
	|	АдминистративныеАдресныеОбъекты0.Наименование0,
	|	АдминистративныеАдресныеОбъекты0.ТипОбъекта0,
	|	АдминистративныеАдресныеОбъекты1.Наименование1,
	|	АдминистративныеАдресныеОбъекты1.ТипОбъекта1,
	|	АдминистративныеАдресныеОбъекты2.Наименование2,
	|	АдминистративныеАдресныеОбъекты2.ТипОбъекта2,
	|	АдминистративныеАдресныеОбъекты3.Наименование3,
	|	АдминистративныеАдресныеОбъекты3.ТипОбъекта3,
	|	АдминистративныеАдресныеОбъекты4.Наименование4,
	|	АдминистративныеАдресныеОбъекты4.ТипОбъекта4,
	|	АдминистративныеАдресныеОбъекты5.Наименование5,
	|	АдминистративныеАдресныеОбъекты5.ТипОбъекта5,
	|	ЕСТЬNULL(АдминистративныеАдресныеОбъекты5.ДополнительныеСведения, ЕСТЬNULL(АдминистративныеАдресныеОбъекты4.ДополнительныеСведения, ЕСТЬNULL(АдминистративныеАдресныеОбъекты3.ДополнительныеСведения, ЕСТЬNULL(АдминистративныеАдресныеОбъекты2.ДополнительныеСведения, ЕСТЬNULL(АдминистративныеАдресныеОбъекты1.ДополнительныеСведения, АдминистративныеАдресныеОбъекты0.ДополнительныеСведения))))),
	|	ЕСТЬNULL(АдминистративныеАдресныеОбъекты5.Уровень, ЕСТЬNULL(АдминистративныеАдресныеОбъекты4.Уровень, ЕСТЬNULL(АдминистративныеАдресныеОбъекты3.Уровень, ЕСТЬNULL(АдминистративныеАдресныеОбъекты2.Уровень, ЕСТЬNULL(АдминистративныеАдресныеОбъекты1.Уровень, АдминистративныеАдресныеОбъекты0.Уровень)))))
	|ИЗ
	|	АдресаПоПолям КАК АдресаПоПолям
	|		ЛЕВОЕ СОЕДИНЕНИЕ Регионы КАК АдминистративныеАдресныеОбъекты0
	|		ПО АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты0.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты1 КАК АдминистративныеАдресныеОбъекты1
	|		ПО (АдминистративныеАдресныеОбъекты0.Идентификатор = АдминистративныеАдресныеОбъекты1.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты1.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты2 КАК АдминистративныеАдресныеОбъекты2
	|		ПО (АдминистративныеАдресныеОбъекты1.Идентификатор = АдминистративныеАдресныеОбъекты2.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты2.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты3 КАК АдминистративныеАдресныеОбъекты3
	|		ПО (АдминистративныеАдресныеОбъекты2.Идентификатор = АдминистративныеАдресныеОбъекты3.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты3.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты4 КАК АдминистративныеАдресныеОбъекты4
	|		ПО (АдминистративныеАдресныеОбъекты3.Идентификатор = АдминистративныеАдресныеОбъекты4.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты4.Ключ
	|		ЛЕВОЕ СОЕДИНЕНИЕ АдминистративныеАдресныеОбъекты5 КАК АдминистративныеАдресныеОбъекты5
	|		ПО (АдминистративныеАдресныеОбъекты4.Идентификатор = АдминистративныеАдресныеОбъекты5.РодительскийИдентификатор)
	|			И АдресаПоПолям.Ключ = АдминистративныеАдресныеОбъекты5.Ключ
	|ГДЕ
	|	АдминистративныеАдресныеОбъекты0.ЭтоМуниципальныйАдрес = ЛОЖЬ
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъекты.Ключ КАК КлючАдреса,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.ИдентификаторУровень0 КАК ИдентификаторУровень0,
	|	АдресныеОбъекты.ИдентификаторУровень1 КАК ИдентификаторУровень1,
	|	АдресныеОбъекты.ИдентификаторУровень2 КАК ИдентификаторУровень2,
	|	АдресныеОбъекты.ИдентификаторУровень3 КАК ИдентификаторУровень3,
	|	АдресныеОбъекты.ИдентификаторУровень4 КАК ИдентификаторУровень4,
	|	АдресныеОбъекты.ИдентификаторУровень5 КАК ИдентификаторУровень5,
	|	АдресныеОбъекты.Наименование0 КАК Наименование0,
	|	АдресныеОбъекты.ТипОбъекта0 КАК ТипОбъекта0,
	|	АдресныеОбъекты.Наименование1 КАК Наименование1,
	|	АдресныеОбъекты.ТипОбъекта1 КАК ТипОбъекта1,
	|	АдресныеОбъекты.Наименование2 КАК Наименование2,
	|	АдресныеОбъекты.ТипОбъекта2 КАК ТипОбъекта2,
	|	АдресныеОбъекты.Наименование3 КАК Наименование3,
	|	АдресныеОбъекты.ТипОбъекта3 КАК ТипОбъекта3,
	|	АдресныеОбъекты.Наименование4 КАК Наименование4,
	|	АдресныеОбъекты.ТипОбъекта4 КАК ТипОбъекта4,
	|	АдресныеОбъекты.Наименование5 КАК Наименование5,
	|	АдресныеОбъекты.ТипОбъекта5 КАК ТипОбъекта5,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.Уровень0 КАК Уровень0,
	|	АдресныеОбъекты.Уровень1 КАК Уровень1,
	|	АдресныеОбъекты.Уровень2 КАК Уровень2,
	|	АдресныеОбъекты.Уровень3 КАК Уровень3,
	|	АдресныеОбъекты.Уровень4 КАК Уровень4,
	|	АдресныеОбъекты.Уровень5 КАК Уровень5
	|ИЗ
	|	АдресныеОбъекты КАК АдресныеОбъекты
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъекты.Ключ КАК КлючДома,
	|	ДомаЗданияСтроения.АдресныйОбъект КАК АдресныйОбъект,
	|	ДомаЗданияСтроения.ДополнительныеАдресныеСведения КАК ДополнительныеСведения,
	|	ДомаЗданияСтроения.Строения КАК Строения,
	|	Сведения.Идентификатор КАК Идентификатор,
	|	Сведения.КодСубъектаРФ КАК КодСубъектаРФ,
	|	Сведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	Сведения.ОКТМО КАК ОКТМО,
	|	Сведения.OKATO КАК OKATO,
	|	Сведения.КодУчасткаИФНСЮЛ КАК КодУчасткаИФНСЮЛ,
	|	Сведения.КодУчасткаИФНСФЛ КАК КодУчасткаИФНСФЛ,
	|	Сведения.КодИФНСЮЛ КАК КодИФНСЮЛ,
	|	Сведения.КодИФНСФЛ КАК КодИФНСФЛ
	|ИЗ
	|	АдресныеОбъекты КАК АдресныеОбъекты
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДомаЗданияСтроения КАК ДомаЗданияСтроения
	|		ПО (ДомаЗданияСтроения.АдресныйОбъект = АдресныеОбъекты.Идентификатор)
	|			И (НЕ ДомаЗданияСтроения.Строения ЕСТЬ NULL)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК Сведения
	|		ПО (Сведения.Идентификатор = ДомаЗданияСтроения.ДополнительныеАдресныеСведения)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	АдресныеОбъекты.Ключ КАК КлючУчастки,
	|	ЗемельныеУчастки.АдресныйОбъект КАК АдресныйОбъект,
	|	ЗемельныеУчастки.Участки КАК Участки,
	|	Сведения.Идентификатор КАК Идентификатор,
	|	Сведения.КодСубъектаРФ КАК КодСубъектаРФ,
	|	Сведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	Сведения.ОКТМО КАК ОКТМО,
	|	Сведения.OKATO КАК OKATO,
	|	Сведения.КодУчасткаИФНСЮЛ КАК КодУчасткаИФНСЮЛ,
	|	Сведения.КодУчасткаИФНСФЛ КАК КодУчасткаИФНСФЛ,
	|	Сведения.КодИФНСЮЛ КАК КодИФНСЮЛ,
	|	Сведения.КодИФНСФЛ КАК КодИФНСФЛ
	|ИЗ
	|	АдресныеОбъекты КАК АдресныеОбъекты
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗемельныеУчастки КАК ЗемельныеУчастки
	|		ПО (ЗемельныеУчастки.АдресныйОбъект = АдресныеОбъекты.Идентификатор)
	|			И (НЕ ЗемельныеУчастки.Участки ЕСТЬ NULL)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК Сведения
	|		ПО (Сведения.Идентификатор = ЗемельныеУчастки.ДополнительныеАдресныеСведения)";
	
	Возврат ТекстЗапроса;

КонецФункции

Процедура АктуализироватьДанныеОРегионе(Знач Адрес, Знач КодСубъектаРФ, Знач Результат)

	Результат.АдресПроверен   = Истина;
	Результат.АдресКорректный = Ложь;

	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	АдресныеОбъекты.Наименование КАК Наименование,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|ГДЕ
	|	АдресныеОбъекты.КодСубъектаРФ = &КодСубъектаРФ
	|	И АдресныеОбъекты.Уровень = &Уровень";

	Запрос.УстановитьПараметр("КодСубъектаРФ", КодСубъектаРФ);
	Запрос.УстановитьПараметр("Уровень", 1);
	
	РезультатЗапроса = Запрос.Выполнить();

	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	СтароеНаименование = Адрес.area + " " + Адрес.areaType;
	НовоеНаименование  = "";

	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		
		НовыйАдрес = ОбщегоНазначения.СкопироватьРекурсивно(Адрес);
		НовыйАдрес.area     = ВыборкаДетальныеЗаписи.Наименование;
		НовыйАдрес.areaType = ВыборкаДетальныеЗаписи.ТипОбъекта;
		НовыйАдрес.areaId   = ВыборкаДетальныеЗаписи.Идентификатор;
		НовоеНаименование   = АдресныйКлассификатор.НаименованиеРегионаПоКоду(КодСубъектаРФ);
		
		Результат.Варианты.Добавить(НовыйАдрес);
		
	КонецЦикла;

	Если ПустаяСтрока(НовоеНаименование) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Регион ""%1"" устарел'"), СтароеНаименование);
	Иначе
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Регион ""%1"" был переименован в ""%2""'"), СтароеНаименование, НовоеНаименование);
	КонецЕсли;
	ДобавитьОшибкуПроверкиАдресаПоКлассификатору(Результат.Ошибки, "СубъектРФ", ТекстОшибки);

КонецПроцедуры

Процедура АнализАдресныхОбъектов(Результаты, Адреса, Знач СписокПроверяемыхУровней, ВариантыАдресов,
	ПроверятьУстареваниеАдресов)

	ТаблицаАдресов = ВариантыАдресов.Выгрузить();

	Для Каждого КлючЗначение Из Адреса Цикл

		Результат = Результаты[КлючЗначение.Ключ]; // см. РезультатПроверкиАдреса

		Если Результаты[КлючЗначение.Ключ].АдресПроверен Тогда
			Продолжить;
		КонецЕсли;

		ОшибкиПроверки = Результат.Ошибки;

		НайденныеАдреса           = ТаблицаАдресов.НайтиСтроки(Новый Структура("КлючАдреса", КлючЗначение.Ключ));
		КакиеУровниПроверять      = СписокПроверяемыхУровней[КлючЗначение.Ключ];
		СписокНекорректныхАдресов = Новый Массив;
		Адрес                     = КлючЗначение.Значение;

		ПроверитьКорректностьАдресов(СписокНекорректныхАдресов, КакиеУровниПроверять, Адрес, НайденныеАдреса,
			ОшибкиПроверки);

		Если СписокНекорректныхАдресов.Количество() = 0 Тогда

			Результат.АдресКорректный = Ложь;
			Результат.АдресПроверен = Истина;
			Если ПроверятьУстареваниеАдресов Тогда
				//@skip-check query-in-loop - редкие штучные запросы, только для устаревшего адреса.
				НовыеАдреса = АктуальныйАдресДляИсторического(Адрес); // Вызывается, только если адрес устарел.
				Если НовыеАдреса.АдресНайден Тогда
					Результат.Варианты = НовыеАдреса.Варианты;
					ОшибкиПроверки.Очистить();
					ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, "Представление",
						СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Адрес некорректный, т.к. он устарел
								   |Актуальный: %1'"), НовыеАдреса.Представление));
				КонецЕсли;
			КонецЕсли;
		Иначе
			ОшибкиПроверки.Очистить();
			Результат.АдресКорректный = Истина;
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

Процедура ПроверитьКорректностьАдресов(СписокНекорректныхАдресов, Знач КакиеУровниПроверять, Адрес,
	Знач НайденныеАдреса, ОшибкиПроверки)

	Для Каждого АдресСтрока Из НайденныеАдреса Цикл

		Если КакиеУровниПроверять["distict"] <> Неопределено И АдресСтрока["Наименование"
			+ КакиеУровниПроверять["Distict"]] = Null Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, "СвРайМО/Район",
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Район ""%1"" отсутствует в адресном классификаторе'"), 
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.District, Адрес.DistrictType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("area", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Субъект РФ'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Субъект РФ ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес["Area"], Адрес["AreaType"], Истина)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("munDistrict", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Муниципальный район'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Муниципальный район ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.MunDistrict, Адрес.MunDistrictType)));
			Продолжить;

		КонецЕсли;
			
		Если Не ДанныеУровняКорректные("distict", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Район'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Район ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.District, Адрес.DistrictType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("settlement", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Поселение'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Поселение ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.Settlement, Адрес.SettlementType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("city", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Город'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Город ""%1"" отсутствует в адресном классификаторе'"), 
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.City, Адрес.CityType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("territory", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Территория'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Территория ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.Territory, Адрес.TerritoryType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("locality", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Населенный пункт'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Населенный пункт ""%1"" отсутствует в адресном классификаторе'"),
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.Locality, Адрес.LocalityType)));
			Продолжить;

		КонецЕсли;

		Если Не ДанныеУровняКорректные("street", АдресСтрока, КакиеУровниПроверять) Тогда

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, НСтр("ru = 'Улица'"),
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Улица ""%1"" отсутствует в адресном классификаторе'"), 
					СоединитьНаименованиеИТипАдресногоОбъекта(Адрес.Street, Адрес.StreetType)));
			Продолжить;

		КонецЕсли;

		СписокНекорректныхАдресов.Добавить(АдресСтрока);
	КонецЦикла;

КонецПроцедуры

Процедура АнализДомовИДополнительныхСведений(Результаты, Знач Адреса, Знач ДомаИСведения, Знач Участки)

	ТаблицаДомов    = ДомаИСведения.Выгрузить();
	ТаблицаУчастков = Участки.Выгрузить();
	Для Каждого КлючЗначение Из Адреса Цикл

		Результат = Результаты[КлючЗначение.Ключ];
		Если Не Результат.АдресКорректный Тогда
			Продолжить;
		КонецЕсли;

		Если Результаты[КлючЗначение.Ключ].АдресПроверен Тогда
			Продолжить;
		КонецЕсли;

		Адрес = КлючЗначение.Значение;
		ОшибкиПроверки = Результат.Ошибки;

		Если ЗначениеЗаполнено(Адрес.stead) Тогда
			ПроверитьУчастки(Адрес.stead, КлючЗначение.Ключ, ОшибкиПроверки, Результат, ТаблицаУчастков);
			Продолжить;
		КонецЕсли;
		ДомВАдресе = ОписаниеДомаИЗемельногоУчастка();
		ИзвлечьСтроенияВОписаниеДома(ДомВАдресе, Адрес);

		Если ПустаяСтрока(ДомВАдресе.НомерДома) И Адрес.Buildings.Количество() = 0 Тогда
			Продолжить; // У адреса нет домов, корпусов и строений. Возможно это почтовый адреса с а/я или до востребования.
		КонецЕсли;

		ДомКорректный = ДомаИСведения.Пустой(); // Домов нет, любой дом считаем корректным.
		ПочтовыйИндекс = 0;

		ОписаниеТиповСтрока100 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100));
		ПохожиеВарианты = Новый ТаблицаЗначений;
		ПохожиеВарианты.Колонки.Добавить("Дом", ОписаниеТиповСтрока100);
		ПохожиеВарианты.Индексы.Добавить("Дом");

		НайденныеДома = ТаблицаДомов.НайтиСтроки(Новый Структура("КлючДома", КлючЗначение.Ключ));
		Для Каждого ИнформацияОДомах Из НайденныеДома Цикл

			Если ПустаяСтрока(ИнформацияОДомах.Строения) Тогда
				Продолжить;
			КонецЕсли;

			СтрокаСоСпискомДомов = ИнформацияОДомах.Строения.Получить();

			Если ЗначениеЗаполнено(СтрокаСоСпискомДомов) Тогда
				МассивДомов = СтрРазделить(СтрокаСоСпискомДомов, Символы.ПС, Ложь);

				Для Каждого СтрокаДом Из МассивДомов Цикл

					ОписаниеДома = ОписаниеДома(СтрокаДом);

					Если СтрСравнить(ДомВАдресе.НомерДома, ОписаниеДома.НомерДома) = 0 Тогда

						Если СтрСравнить(ДомВАдресе.НаименованиеДома, ОписаниеДома.НаименованиеДома) = 0 Тогда

							Если СтрСравнить(ДомВАдресе.ДополнительныйНомерДома1,
											 ОписаниеДома.ДополнительныйНомерДома1) = 0
							   И СтрСравнить(ДомВАдресе.НаименованиеДополнительногоДома1,
											 ОписаниеДома.НаименованиеДополнительногоДома1) = 0 
							   И СтрСравнить(ДомВАдресе.ДополнительныйНомерДома2, 
											 ОписаниеДома.ДополнительныйНомерДома2) = 0
							   И СтрСравнить(ДомВАдресе.НаименованиеДополнительногоДома2,
											 ОписаниеДома.НаименованиеДополнительногоДома2) = 0 Тогда
								ДомКорректный = Истина;
								ПочтовыйИндекс = ИнформацияОДомах.ПочтовыйИндекс;
								Прервать;
							Иначе
									
								// дома совпал, но корпус или строение отличается
								НовыйВариант     = ПохожиеВарианты.Добавить();
								НовыйВариант.Дом = ПредставлениеДомаИСтроений(ОписаниеДома);

							КонецЕсли;

						Иначе
								
								// тип дома не совпал
							ТекстПроДом = НРег(ОписаниеДома.НаименованиеДома) + " """ + ОписаниеДома.НомерДома + """";
							Если ПохожиеВарианты.Найти(ТекстПроДом, "Дом") = Неопределено Тогда
								НовыйВариант     = ПохожиеВарианты.Добавить();
								НовыйВариант.Дом = ТекстПроДом;
							КонецЕсли;

						КонецЕсли;

					КонецЕсли;

					Если ДомКорректный = Истина Тогда
						Прервать;
					КонецЕсли;

				КонецЦикла;

			КонецЕсли;

		КонецЦикла;

		Если Не ДомКорректный Тогда

			ПолеСОшибкой = ?(ЗначениеЗаполнено(ДомВАдресе.НомерДома), "Дом", "Строение");

			ПредставлениеДома = ПредставлениеДомаИСтроений(ДомВАдресе);
			ПредставлениеДома = ВРег(Лев(ПредставлениеДома, 1)) + Сред(ПредставлениеДома, 2);

			Если ПохожиеВарианты.Количество() > 0 Тогда

				ПервыйВариант = ПохожиеВарианты[0].Дом;

				Если ПохожиеВарианты.Количество() = 1 Тогда

					ТекстПодсказки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'но есть %1'"),
						ПервыйВариант);

				Иначе

					Если ПохожиеВарианты.Количество() = 2 Тогда

						ШаблонПодсказки = НСтр("ru = 'но есть %1 или %2'");
						ВторойВариант = ПохожиеВарианты[1].Дом;

					Иначе

						ШаблонПодсказки = НСтр("ru = 'но есть %1 и другие варианты (%2)'");
						ВторойВариант = Формат(ПохожиеВарианты.Количество() - 1, "ЧГ=0");

					КонецЕсли;

					ТекстПодсказки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонПодсказки,
						ПервыйВариант, ВторойВариант);

				КонецЕсли;

				ТекстПодсказки = ", " + ТекстПодсказки;
			Иначе

				ТекстПодсказки = "";

			КонецЕсли;

			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, ПолеСОшибкой,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = '%1 отсутствует в адресном классификаторе%2'"), ПредставлениеДома, ТекстПодсказки));

			Результат.АдресКорректный = Ложь;
			Результат.АдресПроверен = Истина;

			Продолжить;
		
		КонецЕсли;
		
		ПочтовыйИндекс = Формат(ПочтовыйИндекс, "ЧГ=0");
		Если СтрСравнить(ПочтовыйИндекс, Адрес.ZipCode) <> 0 Тогда
			Результат.АдресКорректный = Ложь;
			
			НовыйАдрес = ОбщегоНазначения.СкопироватьРекурсивно(Адрес);
			НовыйАдрес.ZipCode = ПочтовыйИндекс;
			Результат.Варианты.Добавить(НовыйАдрес);
			
			ДополнительныйТекст = ?(ЗначениеЗаполнено(ПочтовыйИндекс), " " + НСтр("ru = 'Возможно, правильный индекс'")
				+ " " + ПочтовыйИндекс, "");
			ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, "Индекс",
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Индекс %1 не соответствует адресу.%2'"), Адрес.ZipCode, ДополнительныйТекст));
				
		КонецЕсли;
		Результат.АдресПроверен = Истина;

	КонецЦикла;

КонецПроцедуры

Процедура ИзвлечьСтроенияВОписаниеДома(ОписаниеДома, Адрес)
	
	Если Адрес.Свойство("houseNumber") Тогда
		ОписаниеДома.НомерДома = Адрес.houseNumber;
		ОписаниеДома.НаименованиеДома = ?(ЗначениеЗаполнено(ОписаниеДома.НомерДома), Адрес.houseType, "");
	ИначеЕсли Адрес.Свойство("number") Тогда
		ОписаниеДома.НомерДома = Адрес.number;
		ОписаниеДома.НаименованиеДома = ?(ЗначениеЗаполнено(ОписаниеДома.НомерДома), Адрес.type, "");
	КонецЕсли;
	
	Если Адрес.Buildings.Количество() > 0 Тогда
		
		Если ЗначениеЗаполнено(ОписаниеДома.НомерДома) Тогда
			ОписаниеДома.ДополнительныйНомерДома1         = Адрес.Buildings[0].number;
			ОписаниеДома.НаименованиеДополнительногоДома1 = Адрес.Buildings[0].type;
		Иначе
			ОписаниеДома.НомерДома        = Адрес.Buildings[0].number;
			ОписаниеДома.НаименованиеДома = Адрес.Buildings[0].type;
		КонецЕсли;
		
		Если Адрес.Buildings.Количество() > 1 Тогда
			
			Если ЗначениеЗаполнено(ОписаниеДома.ДополнительныйНомерДома1) Тогда
				ОписаниеДома.ДополнительныйНомерДома2         = Адрес.Buildings[1].number;
				ОписаниеДома.НаименованиеДополнительногоДома2 = Адрес.Buildings[1].type;
			Иначе
				ОписаниеДома.ДополнительныйНомерДома1         = Адрес.Buildings[1].number;
				ОписаниеДома.НаименованиеДополнительногоДома1 = Адрес.Buildings[1].type;
			КонецЕсли;
			
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры


// Параметры:
//  СтрокаДом - Строка
// 
// Возвращаемое значение:
//  Структура:
//   * ДомЧислом - Число
//   * НомерДома - Строка
//   * ДополнительныйНомерДома1 - Строка
//   * ДополнительныйНомерДома2 - Строка
//   * ТипДома - Число
//   * ДополнительныйТипДома1 - Число
//   * ДополнительныйТипДома2 - Число
//   * НаименованиеДома - Строка
//   * НаименованиеДополнительногоДома1 - Строка
//   * НаименованиеДополнительногоДома2 - Строка
//   * ИдентификаторДома - УникальныйИдентификатор
//   * Индекс - Строка
//   * ОКТМО - Строка
//   * ОКАТО - Строка
//   * КодИФНСФЛ - Строка
//   * КодИФНСЮЛ - Строка
//   * КодУчасткаИФНСФЛ - Строка
//   * КодУчасткаИФНСЮЛ - Строка
//   * КодКЛАДР - Строка
//
Функция ОписаниеДома(СтрокаДом)

	ТипЧисло = Новый ОписаниеТипов("Число");
	НаименованиеДомов = АдресныйКлассификаторПовтИсп.НаименованияВладенийИСтроений();

	НомерДома = СтрРазделить(Сред(СтрокаДом, 25), Символы.Таб, Истина);

	ОписаниеДома = ОписаниеДомаИЗемельногоУчастка();

	ОписаниеДома.ИдентификаторДома = УникальныйИдентификаторИзСтроки64(Лев(СтрокаДом, 24));
	Если ЗначениеЗаполнено(НомерДома[0]) Тогда

		ТипИНомерДома = СтрРазделить(НомерДома[0], Символы.НПП);
		ОписаниеДома.ТипДома      = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
		ОписаниеДома.НомерДома = ТипИНомерДома[1];

		Если СтрСравнить(ОписаниеДома.НомерДома, "НЕТ") = 0 Тогда
			ОписаниеДома.НомерДома = "";
		КонецЕсли;

		Если ЗначениеЗаполнено(ОписаниеДома.ТипДома) Тогда
			ОписаниеДома.НаименованиеДома = НаименованиеДомов.Владения.Получить(ОписаниеДома.ТипДома);
		КонецЕсли;
	КонецЕсли;

	Если НомерДома.Количество() > 1 Тогда

		ТипИНомерДома = СтрРазделить(НомерДома[1], Символы.НПП);
		ОписаниеДома.ДополнительныйТипДома1   = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
		ОписаниеДома.ДополнительныйНомерДома1 = ТипИНомерДома[1];
		ОписаниеДома.НаименованиеДополнительногоДома1 = НаименованиеДомов.Строения.Получить(
			ОписаниеДома.ДополнительныйТипДома1);

	КонецЕсли;

	Если НомерДома.Количество() > 2 Тогда

		ТипИНомерДома = СтрРазделить(НомерДома[2], Символы.НПП);
		ОписаниеДома.ДополнительныйТипДома2   = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
		ОписаниеДома.ДополнительныйНомерДома2 = ТипИНомерДома[1];
		ОписаниеДома.НаименованиеДополнительногоДома2 = НаименованиеДомов.Строения.Получить(
			ОписаниеДома.ДополнительныйТипДома2);

	КонецЕсли;

	Возврат ОписаниеДома

КонецФункции

Процедура ПроверитьУчастки(Знач Участок, Знач ИндексАдреса, Знач ОшибкиПроверки, Знач Результат, Знач ТаблицаУчастков)

	// Проверка участка
	НайденныеУчастки = ТаблицаУчастков.НайтиСтроки(Новый Структура("КлючУчастки", ИндексАдреса));
	Для Каждого ИнформацияОУчастках Из НайденныеУчастки Цикл
	
		Если ПустаяСтрока(ИнформацияОУчастках.Участки) Тогда
			Продолжить;
		КонецЕсли;
	
		СтрокаСоСпискомУчастков = ИнформацияОУчастках.Участки.Получить();
		Если ЗначениеЗаполнено(СтрокаСоСпискомУчастков) Тогда
	
			НаборУчастков = СтрРазделить(СтрокаСоСпискомУчастков, Символы.ПС, Ложь);
	
			Для Каждого СтрокаУчасток Из НаборУчастков Цикл
				НомерУчастка = Сред(СтрокаУчасток, 25);
	
				Если СтрСравнить(НомерУчастка, Участок) = 0 Тогда
					Результат.АдресКорректный = Истина;
					Результат.АдресПроверен   = Истина;
					Возврат;
				КонецЕсли;
	
			КонецЦикла;
	
		КонецЕсли;

	КонецЦикла;

	ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ОшибкиПроверки, "Дом",
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Земельный участок %1 отсутствует в адресном классификаторе'"), Участок));

	Результат.АдресКорректный = Ложь;
	Результат.АдресПроверен = Истина;

КонецПроцедуры

#Область КонвертацияАдресаБазыВАдресВебСервиса

Функция АдресДляПередачиВСервис(Адрес)

	Результат = НовыйАдресДляДляПередачиВСервис();

	ЗаполнитьЗначенияСвойств(Результат, Адрес,, "apartments,buildings,munLevels,admLevels");
	
	Результат.Вставить("ifnsFlAreaCode", Адрес.ifnsFLAreaCode);
	Результат.Вставить("ifnsFlCode", Адрес.ifnsFLCode);
	Результат.Вставить("ifnsUlAreaCode", Адрес.ifnsULAreaCode);
	Результат.Вставить("ifnsUlCode", Адрес.ifnsULCode);
	Результат.Вставить("steadNumber", Адрес.stead);
	Если ЗначениеЗаполнено(Адрес.stead) Тогда
		Результат.steadType = ТипАдресногоОбъектаУчасток();
	КонецЕсли;

	Результат.Вставить("apartments", Новый Массив);
	Для Каждого Дом Из Адрес.apartments Цикл
		ВебДом = НовыйДомДляДляПередачиВСервис();
		ВебДом.type = Дом.Type;
		ВебДом.number = Дом.Number;
		Результат.apartments.Добавить(ВебДом);
	КонецЦикла;

	Результат.Вставить("buildings", Новый Массив);
	Для Каждого Дом Из Адрес.buildings Цикл
		ВебДом       = НовыйДомДляДляПередачиВСервис();
		ВебДом.type   = Дом.Type;
		ВебДом.number = Дом.Number;
		Результат.buildings.Добавить(ВебДом);
	КонецЦикла;
	
	Результат.version   = ВерсияJSON(Адрес);
	Результат.admLevels = Адрес.admLevels;
	Результат.munLevels = Адрес.munLevels;

	Результат.munValue = ПредставлениеАдреса(Адрес, МуниципальныйАдрес());
	Результат.value = ПредставлениеАдреса(Адрес, АдминистративноТерриториальныйАдрес());
	
	Возврат Результат;

КонецФункции

Функция ТипАдресногоОбъектаУчасток()

	Возврат "участок";

КонецФункции

Функция НовыйАдресДляДляПередачиВСервис()

	Адрес = Новый Структура;
	Адрес.Вставить("version");
	Адрес.Вставить("ZIPcode"); // postalCode -> ZIPCode
	Адрес.Вставить("apartments"); // Массив из см. ДомДляДляПередачиВСервис
	Адрес.Вставить("area");
	Адрес.Вставить("areaCode");
	Адрес.Вставить("areaId");
	Адрес.Вставить("areaType");
	Адрес.Вставить("buildings"); // Массив из см. ДомДляДляПередачиВСервис
	Адрес.Вставить("city");
	Адрес.Вставить("cityDistrict");
	Адрес.Вставить("cityDistrictId");
	Адрес.Вставить("cityDistrictType");
	Адрес.Вставить("cityId");
	Адрес.Вставить("cityType");
	Адрес.Вставить("codeKLADR"); // code -> codeKLADR
	Адрес.Вставить("district");
	Адрес.Вставить("districtId");
	Адрес.Вставить("districtType");
	Адрес.Вставить("houseId");
	Адрес.Вставить("houseType");
	Адрес.Вставить("houseNumber"); // house -> houseNumber
	Адрес.Вставить("id");
	Адрес.Вставить("ifnsFlAreaCode");
	Адрес.Вставить("ifnsFlCode");
	Адрес.Вставить("ifnsUlAreaCode");
	Адрес.Вставить("ifnsUlCode");
	Адрес.Вставить("locality");
	Адрес.Вставить("localityId");
	Адрес.Вставить("localityType");
	Адрес.Вставить("munDistrict");
	Адрес.Вставить("munDistrictId");
	Адрес.Вставить("munDistrictType");
	Адрес.Вставить("okato");
	Адрес.Вставить("oktmo");
	Адрес.Вставить("oktmoBudget");
	Адрес.Вставить("settlement");
	Адрес.Вставить("settlementId");
	Адрес.Вставить("settlementType");
	Адрес.Вставить("street");
	Адрес.Вставить("streetId");
	Адрес.Вставить("streetType");
	Адрес.Вставить("steadNumber");
	Адрес.Вставить("steadId");
	Адрес.Вставить("steadType");
	Адрес.Вставить("territory");
	Адрес.Вставить("territoryId");
	Адрес.Вставить("territoryType");
	Адрес.Вставить("value");
	Адрес.Вставить("munValue");
	Адрес.Вставить("munLevels", Новый Массив);
	Адрес.Вставить("admLevels", Новый Массив);

	Возврат Адрес;

КонецФункции

Функция НовыйДомДляДляПередачиВСервис()

	Дом = Новый Структура;
	Дом.Вставить("type");
	Дом.Вставить("number");

	Возврат Дом;

КонецФункции

#КонецОбласти

#Область КонвертацияАдресВебСервисаВАдресБазы

Функция АдресДляСохраненияВБазе(Адрес, Муниципальный = Истина)

	Результат = ОписаниеНовойКонтактнойИнформации();
	ЗаполнитьЗначенияСвойств(Результат, Адрес);

	Для Каждого ПолеАдреса Из Результат Цикл
		Если ПолеАдреса.Значение = Неопределено Тогда
			Результат[ПолеАдреса.Ключ] = "";
		КонецЕсли;
	КонецЦикла;

	Если Муниципальный Тогда
		Результат.addressType = МуниципальныйАдрес();
		Результат.value = Адрес.munValueWithPostalCode;
	Иначе
		Результат.addressType = АдминистративноТерриториальныйАдрес();
		Результат.value = Адрес.valueWithPostalCode;
	КонецЕсли;

	Результат.houseType = ТРег(Результат.houseType);
	
	// Зависит от версии веб-сервиса
	Если Адрес.Свойство("steadNumber") Тогда
		Результат.stead = Строка(Адрес.steadNumber);
	КонецЕсли;

	Для Каждого Строение Из Результат.buildings Цикл
		Строение.type = ТРег(Строение.type);
	КонецЦикла;

	Для Каждого Помещение Из Результат.apartments Цикл
		Помещение.type = ТРег(Помещение.type);
	КонецЦикла;

	Результат.country = ОсновнаяСтрана();

	Возврат Результат;

КонецФункции

#КонецОбласти

// ОКТМО 

Функция СведенияПоСпискуОКМТО(СписокОКТМО) Экспорт

	Результат = Новый Соответствие;

	СведенияОЗагрузкеСубъектовРФ = СведенияОЗагрузкеСубъектовРФ();

	ТипЧисло = ОбщегоНазначения.ОписаниеТипаЧисло(11);

	ТаблицаОКТМО = Новый ТаблицаЗначений;
	ТаблицаОКТМО.Колонки.Добавить("ОКТМО", ТипЧисло);
	ТаблицаОКТМО.Колонки.Добавить("КлючЗаписиОКТМО", ОбщегоНазначения.ОписаниеТипаЧисло(3));

	ТаблицаОКТМОВебСервис = ТаблицаОКТМО.Скопировать();

	Для Каждого ЗаписьОКТМО Из СписокОКТМО Цикл
		ОКТМОЧислом = ТипЧисло.ПривестиЗначение(ЗаписьОКТМО.Значение);

		Если СтрНачинаетсяС(ЗаписьОКТМО.Значение, "118") Или СтрНачинаетсяС(ЗаписьОКТМО.Значение, "718")
			Или СтрНачинаетсяС(ЗаписьОКТМО.Значение, "719") Тогда
			КодОКТМОРегиона = Лев(ЗаписьОКТМО.Значение, 3);
		Иначе
			КодОКТМОРегиона = Лев(ЗаписьОКТМО.Значение, 2);
		КонецЕсли;
		НайденныеСтроки = СведенияОЗагрузкеСубъектовРФ.НайтиСтроки(Новый Структура("ОКТМО", КодОКТМОРегиона));
		Если НайденныеСтроки.Количество() = 0 Тогда
			Результат.Вставить(ЗаписьОКТМО.Ключ, Неопределено);
			Продолжить;
		КонецЕсли;
		СведенияОРегионе = НайденныеСтроки[0];
		Если ОКТМОЧислом > 0 Тогда

			Если СведенияОРегионе.Загружено И Не СведенияОРегионе.Устарело Тогда
				НоваяСтрокаОКТМО = ТаблицаОКТМО.Добавить();
			Иначе
				НоваяСтрокаОКТМО = ТаблицаОКТМОВебСервис.Добавить();
			КонецЕсли;

			НоваяСтрокаОКТМО.ОКТМО = ОКТМОЧислом;
			НоваяСтрокаОКТМО.КлючЗаписиОКТМО = ЗаписьОКТМО.Ключ;
		Иначе
			Результат.Вставить(ЗаписьОКТМО.Ключ, Неопределено);
		КонецЕсли;
	КонецЦикла;

	Если ТаблицаОКТМО.Количество() > 0 Тогда
		СведенияПоСпискуОКМТОЗагруженныеДанные(ТаблицаОКТМО, Результат);
	КонецЕсли;

	Если ТаблицаОКТМОВебСервис.Количество() > 0 Тогда
		СведенияПоСпискуОКМТОВебСервис(ТаблицаОКТМОВебСервис, Результат);
	КонецЕсли;

	Возврат Результат;

КонецФункции

Функция СведенияПоСпискуОКМТОЗагруженныеДанные(ТаблицаОКТМО, Результат)

	Запрос = Новый Запрос;
	
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	СписокОКТМО.ОКТМО КАК ОКТМО,
	|	СписокОКТМО.КлючЗаписиОКТМО КАК КлючЗаписиОКТМО
	|ПОМЕСТИТЬ СписокОКТМО
	|ИЗ
	|	&СписокОКТМО КАК СписокОКТМО
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СписокОКТМО.КлючЗаписиОКТМО КАК КлючЗаписиОКТМО,
	|	ДополнительныеСведения.КодСубъектаРФ КАК КодСубъектаРФ,
	|	ДополнительныеСведения.ПочтовыйИндекс КАК ПочтовыйИндекс,
	|	ДополнительныеСведения.ОКТМО КАК ОКТМО,
	|	ДополнительныеСведения.OKATO КАК OKATO,
	|	ДополнительныеСведения.КодУчасткаИФНСЮЛ КАК КодУчасткаИФНСЮЛ,
	|	ДополнительныеСведения.КодУчасткаИФНСФЛ КАК КодУчасткаИФНСФЛ,
	|	ДополнительныеСведения.КодИФНСЮЛ КАК КодИФНСЮЛ,
	|	ДополнительныеСведения.КодИФНСФЛ КАК КодИФНСФЛ,
	|	АдресныеОбъекты.Наименование КАК Наименование,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
	|	АдресныеОбъекты.Уровень КАК Уровень,
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.Уровень КАК Уровень0,
	|	АдресныеОбъекты.КодКЛАДР КАК КодКЛАДР,
	|	МуниципальнаяИерархия.РодительскийИдентификатор КАК РодительскийИдентификатор
	|ПОМЕСТИТЬ АдресныеОбъекты0
	|ИЗ
	|	СписокОКТМО КАК СписокОКТМО
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (ДополнительныеСведения.ОКТМО = СписокОКТМО.ОКТМО)
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (ДополнительныеСведения.Идентификатор = АдресныеОбъекты.ДополнительныеАдресныеСведения)
	|		И НЕ АдресныеОбъекты.Идентификатор ЕСТЬ NULL
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия
	|		ПО (АдресныеОбъекты.Идентификатор = МуниципальнаяИерархия.Идентификатор)
	|
	|;
	|
	|ВЫБРАТЬ
	|	АдресныеОбъекты0.КлючЗаписиОКТМО КАК КлючЗаписиОКТМО,
	|	АдресныеОбъекты5.Наименование КАК Наименование5,
	|	АдресныеОбъекты5.ТипОбъекта КАК ТипОбъекта5,
	|	АдресныеОбъекты5.Идентификатор КАК Идентификатор5,
	|	АдресныеОбъекты5.Уровень КАК Уровень5,
	|	АдресныеОбъекты4.Наименование КАК Наименование4,
	|	АдресныеОбъекты4.ТипОбъекта КАК ТипОбъекта4,
	|	АдресныеОбъекты4.Идентификатор КАК Идентификатор4,
	|	АдресныеОбъекты4.Уровень КАК Уровень4,
	|	АдресныеОбъекты3.Наименование КАК Наименование3,
	|	АдресныеОбъекты3.ТипОбъекта КАК ТипОбъекта3,
	|	АдресныеОбъекты3.Идентификатор КАК Идентификатор3,
	|	АдресныеОбъекты3.Уровень КАК Уровень3,
	|	АдресныеОбъекты2.Наименование КАК Наименование2,
	|	АдресныеОбъекты2.ТипОбъекта КАК ТипОбъекта2,
	|	АдресныеОбъекты2.Идентификатор КАК Идентификатор2,
	|	АдресныеОбъекты2.Уровень КАК Уровень2,
	|	АдресныеОбъекты1.Наименование КАК Наименование1,
	|	АдресныеОбъекты1.ТипОбъекта КАК ТипОбъекта1,
	|	АдресныеОбъекты1.Идентификатор КАК Идентификатор1,
	|	АдресныеОбъекты1.Уровень КАК Уровень1,
	|	АдресныеОбъекты0.Наименование КАК Наименование0,
	|	АдресныеОбъекты0.ТипОбъекта КАК ТипОбъекта0,
	|	АдресныеОбъекты0.Идентификатор КАК Идентификатор0,
	|	АдресныеОбъекты0.Уровень КАК Уровень0,
	|	АдресныеОбъекты0.КодКЛАДР КАК КодКЛАДР,
	|	АдресныеОбъекты0.КодСубъектаРФ КАК КодРегиона,
	|	ЕСТЬNULL(АдресныеОбъекты0.ПочтовыйИндекс, """""""""""""""") КАК ПочтовыйИндекс,
	|	ЕСТЬNULL(АдресныеОбъекты0.ОКТМО, """""""""""""""") КАК ОКТМО,
	|	ЕСТЬNULL(АдресныеОбъекты0.OKATO, """""""""""""""") КАК OKATO,
	|	ЕСТЬNULL(АдресныеОбъекты0.КодУчасткаИФНСЮЛ, """""""""""""""") КАК КодУчасткаИФНСЮЛ,
	|	ЕСТЬNULL(АдресныеОбъекты0.КодУчасткаИФНСФЛ, """""""""""""""") КАК КодУчасткаИФНСФЛ,
	|	ЕСТЬNULL(АдресныеОбъекты0.КодИФНСЮЛ, """""""""""""""") КАК КодИФНСЮЛ,
	|	ЕСТЬNULL(АдресныеОбъекты0.КодИФНСФЛ, """""""""""""""") КАК КодИФНСФЛ
	|ИЗ
	|	АдресныеОбъекты0 КАК АдресныеОбъекты0
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия1
	|		ПО (АдресныеОбъекты0.РодительскийИдентификатор = МуниципальнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия2
	|		ПО (МуниципальнаяИерархия1.РодительскийИдентификатор = МуниципальнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия3
	|		ПО (МуниципальнаяИерархия2.РодительскийИдентификатор = МуниципальнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия4
	|		ПО (МуниципальнаяИерархия3.РодительскийИдентификатор = МуниципальнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МуниципальнаяИерархия КАК МуниципальнаяИерархия5
	|		ПО (МуниципальнаяИерархия4.РодительскийИдентификатор = МуниципальнаяИерархия5.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты1
	|		ПО (АдресныеОбъекты1.Идентификатор = МуниципальнаяИерархия1.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты2
	|		ПО (АдресныеОбъекты2.Идентификатор = МуниципальнаяИерархия2.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты3
	|		ПО (АдресныеОбъекты3.Идентификатор = МуниципальнаяИерархия3.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты4
	|		ПО (АдресныеОбъекты4.Идентификатор = МуниципальнаяИерархия4.Идентификатор)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты5
	|		ПО (АдресныеОбъекты5.Идентификатор = МуниципальнаяИерархия5.Идентификатор)
	|ГДЕ
	|	АдресныеОбъекты0.Уровень < &УровеньУлицы";
	
	Запрос.Параметры.Вставить("СписокОКТМО", ТаблицаОКТМО);
	Запрос.УстановитьПараметр("УровеньУлицы", 8);
	
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

	СписокСокращений = АдресныйКлассификаторПовтИсп.СписокСокращений();
	ИменаУровней = ИменаУровнейАдресаПоКодуУровня();
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл

		СведенияПоОКТМО = НовыйСведенияПоОКТМО();
		
		СведенияПоОКТМО.ОКТМО            = ОКТМОИлиОКАТОСтрокой(ВыборкаДетальныеЗаписи.ОКТМО);
		СведенияПоОКТМО.OKATO            = ОКТМОИлиОКАТОСтрокой(ВыборкаДетальныеЗаписи.OKATO);
		СведенияПоОКТМО.КодКЛАДР         = КодКЛАДРСтрокой(ВыборкаДетальныеЗаписи.КодКЛАДР);
		СведенияПоОКТМО.КодУчасткаИФНСЮЛ = Формат(ВыборкаДетальныеЗаписи.КодУчасткаИФНСЮЛ, "ЧГ=0");
		СведенияПоОКТМО.КодУчасткаИФНСФЛ = Формат(ВыборкаДетальныеЗаписи.КодУчасткаИФНСФЛ, "ЧГ=0");
		СведенияПоОКТМО.КодИФНСЮЛ        = Формат(ВыборкаДетальныеЗаписи.КодИФНСЮЛ, "ЧГ=0");
		СведенияПоОКТМО.КодИФНСФЛ        = Формат(ВыборкаДетальныеЗаписи.КодИФНСФЛ, "ЧГ=0");
		СведенияПоОКТМО.КодРегиона       = Формат(ВыборкаДетальныеЗаписи.КодРегиона, "ЧГ=0");
		СведенияПоОКТМО.ПочтовыйИндекс   = ВыборкаДетальныеЗаписи.ПочтовыйИндекс;

		Для НомерСегмента = 0 По 5 Цикл

			НомерСегментаСтрокой = XMLСтрока(НомерСегмента);
			Уровень = ВыборкаДетальныеЗаписи["Уровень" + НомерСегментаСтрокой];
			
			Если ЗначениеЗаполнено(Уровень) Тогда
			
				Если Уровень = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию().district Тогда
					Продолжить;
				КонецЕсли;
				
				ИмяПоля = ИменаУровней[Уровень];
				
				СведенияПоОКТМО[ИмяПоля] = ВыборкаДетальныеЗаписи["Наименование" + НомерСегментаСтрокой];
				СведенияПоОКТМО[ИмяПоля + "ТипКраткий"] = ВыборкаДетальныеЗаписи["ТипОбъекта"
					+ НомерСегментаСтрокой];
				СведенияПоОКТМО[ИмяПоля + "Идентификатор"] = ВыборкаДетальныеЗаписи["Идентификатор"
					+ НомерСегментаСтрокой];
				ПолныеНаименованияСокращений = СписокСокращений.Получить(Строка(Уровень) + ВРег(СведенияПоОКТМО[ИмяПоля
					+ "ТипКраткий"]));
				СведенияПоОКТМО[ИмяПоля + "ТипПолный"] = ПолныеНаименованияСокращений;

			КонецЕсли;

		КонецЦикла;

		НаименованиеРегиона = ПолноеНаименованиеРегиона(СведенияПоОКТМО["Регион"], СведенияПоОКТМО["РегионТипКраткий"]);
		
		СведенияПоОКТМО.КодМуниципальногоРайона = КодМуниципальногоРайона(
			СведенияПоОКТМО["МуниципальныйРайонТипКраткий"],
			СведенияПоОКТМО.ОКТМО,
			ЭтоГородФедеральногоЗначения(НаименованиеРегиона));
			
		СведенияПоОКТМО.КодПоселения = КодПоселения(СведенияПоОКТМО["ПоселениеТипКраткий"]);

		Результат.Вставить(ВыборкаДетальныеЗаписи.КлючЗаписиОКТМО, СведенияПоОКТМО);
	КонецЦикла;

	Возврат Результат;

КонецФункции

Процедура СведенияПоСпискуОКМТОВебСервис(СписокОКТМО, Результат)

	СписокСокращений = АдресныйКлассификаторПовтИсп.СписокСокращений();
	ТипЧисло = Новый ОписаниеТипов("Число");
	
	Для Каждого ЗаписьОКТМО Из СписокОКТМО Цикл
		
		ТекстGETЗапроса = "selectByCode?code=%OKTMO%&codeType=OKTMO";
		ТекстGETЗапроса = СтрЗаменить(ТекстGETЗапроса, "%OKTMO%", ОКТМОИлиОКАТОСтрокой(ЗаписьОКТМО.ОКТМО));
		
		РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);
		
		Если РезультатВебСервис.Отказ Тогда
			Результат.Вставить(ЗаписьОКТМО.КлючЗаписиОКТМО, Неопределено);
			Продолжить;
		КонецЕсли;
		
		СведенияПоОКТМО = НовыйСведенияПоОКТМО();
		
		Для Каждого СтрокаДанных Из РезультатВебСервис.Данные Цикл
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "OKATO", "okato");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ОКТМО", "oktmo"); 
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодИФНСФЛ", "ifnsFlCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодИФНСЮЛ", "ifnsUlCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодКЛАДР", "codeKLADR");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодУчасткаИФНСФЛ", "ifnsFlAreaCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодУчасткаИФНСЮЛ", "ifnsUlAreaCode");
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПочтовыйИндекс",
				ТипЧисло.ПривестиЗначение(СтрокаДанных.ZIPcode), Истина);
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Регион", "area");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионТипКраткий", "areaType");
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионТипПолный",
			СписокСокращений.Получить("1" + ВРег(СведенияПоОКТМО.РегионТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.areaId), Неопределено, Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.areaId))),
				Истина);
			
			НаименованиеРегиона = ПолноеНаименованиеРегиона(СведенияПоОКТМО.Регион, СведенияПоОКТМО.РегионТипКраткий);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодРегиона",
				Строка(АдресныйКлассификатор.КодРегионаПоНаименованию(НаименованиеРегиона)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайон", "munDistrict");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонТипКраткий", "munDistrictType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонТипПолный", 
				СписокСокращений.Получить("3" + ВРег(СведенияПоОКТМО.МуниципальныйРайонТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.munDistrictId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.munDistrictId))), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодМуниципальногоРайона",
				КодМуниципальногоРайона(
				СведенияПоОКТМО.МуниципальныйРайонТипКраткий, СведенияПоОКТМО.ОКТМО, ЭтоГородФедеральногоЗначения(
				НаименованиеРегиона)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Город", "city");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородТипКраткий", "cityType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородТипПолный", 
				СписокСокращений.Получить("5" + ВРег(СведенияПоОКТМО.ГородТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.cityId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.cityId))), Истина); 
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПункт", "locality");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктТипКраткий", "localityType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктТипПолный", 
				СписокСокращений.Получить("6" + ВРег(СведенияПоОКТМО.НаселенныйПунктТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.localityId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.localityId))), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Поселение", "settlement");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеТипКраткий", "settlementType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеТипПолный", 
				СписокСокращений.Получить("4" + ВРег(СведенияПоОКТМО.ПоселениеТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.settlementId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.settlementId))), Истина); 
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодПоселения", 
				КодПоселения(СведенияПоОКТМО.ПоселениеТипКраткий), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Территория", "territory");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияТипКраткий", "territoryType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияТипПолный", 
				СписокСокращений.Получить("7" + ВРег(СведенияПоОКТМО.ТерриторияТипКраткий)), Истина);
			
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.territoryId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.territoryId))), Истина); 
			
		КонецЦикла;
		Результат.Вставить(ЗаписьОКТМО.КлючЗаписиОКТМО, СведенияПоОКТМО);
		
	КонецЦикла;

КонецПроцедуры

Процедура ЗаполнитьЗначениеСвойстваЕслиПустое(Приемник, Источник, ИмяСвойстваПриемника, ИмяСвойстваИлиЗначениеИсточника, ЭтоЗначение = Ложь)
	
	ЗначениеСвойства = ?(ЭтоЗначение, ИмяСвойстваИлиЗначениеИсточника, Источник[ИмяСвойстваИлиЗначениеИсточника]);
	
	Если ЗначениеЗаполнено(Приемник[ИмяСвойстваПриемника]) Или Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ЗначениеСвойства) = Тип("Строка") Тогда
		Приемник[ИмяСвойстваПриемника] = СокрЛП(ЗначениеСвойства);
	Иначе
		Приемник[ИмяСвойстваПриемника] = ЗначениеСвойства;
	КонецЕсли;
	
КонецПроцедуры

Функция ОКТМОИлиОКАТОСтрокой(ОКТМОИлиОКАТО)

	Результат = "";
	Результат = Формат(ОКТМОИлиОКАТО, "ЧРГ=' '; ЧГ=0");
	Если СтрДлина(Результат) = 7 Или СтрДлина(Результат) = 10 Тогда
		Возврат "0" + Результат;
	КонецЕсли;

	Возврат Результат;

КонецФункции

Функция ПолноеНаименованиеРегиона(НаименованиеРегиона, ТипРегиона)
	Возврат СокрЛП(НаименованиеРегиона + " " + ТипРегиона);
КонецФункции

Функция ИменаУровнейАдресаПоКодуУровня()
	
	Уровни = Новый Соответствие;

	Уровни.Вставить(1, "Регион");
	Уровни.Вставить(2, "Район");
	Уровни.Вставить(3, "МуниципальныйРайон");
	Уровни.Вставить(4, "Поселение");
	Уровни.Вставить(5, "Город");
	Уровни.Вставить(6, "НаселенныйПункт");
	Уровни.Вставить(7, "Территория");

	Возврат Уровни;
КонецФункции

Функция НовыйСведенияПоОКТМО()

	Результат = Новый Структура;
	Результат.Вставить("КодРегиона", "");
	Результат.Вставить("Регион", "");
	Результат.Вставить("РегионТипПолный", "");
	Результат.Вставить("РегионТипКраткий", "");
	Результат.Вставить("РегионИдентификатор", Неопределено);
	Результат.Вставить("МуниципальныйРайон", "");
	Результат.Вставить("МуниципальныйРайонТипПолный ", "");
	Результат.Вставить("МуниципальныйРайонТипКраткий", "");
	Результат.Вставить("МуниципальныйРайонИдентификатор", Неопределено);
	Результат.Вставить("КодМуниципальногоРайона", "");
	Результат.Вставить("Поселение", "");
	Результат.Вставить("ПоселениеТипПолный", "");
	Результат.Вставить("ПоселениеТипКраткий", "");
	Результат.Вставить("ПоселениеИдентификатор", Неопределено);
	Результат.Вставить("КодПоселения", "");
	Результат.Вставить("Город", "");
	Результат.Вставить("ГородТипПолный", "");
	Результат.Вставить("ГородТипКраткий", "");
	Результат.Вставить("ГородИдентификатор", Неопределено);
	Результат.Вставить("НаселенныйПункт", "");
	Результат.Вставить("НаселенныйПунктТипПолный", "");
	Результат.Вставить("НаселенныйПунктТипКраткий", "");
	Результат.Вставить("НаселенныйПунктИдентификатор", Неопределено);
	Результат.Вставить("Территория", "");
	Результат.Вставить("ТерриторияТипПолный", "");
	Результат.Вставить("ТерриторияТипКраткий", "");
	Результат.Вставить("ТерриторияИдентификатор", Неопределено);
	Результат.Вставить("ПочтовыйИндекс", 0);
	Результат.Вставить("OKATO", "");
	Результат.Вставить("ОКТМО", "");
	Результат.Вставить("КодКЛАДР", "");
	Результат.Вставить("КодИФНСФЛ", "");
	Результат.Вставить("КодИФНСЮЛ", "");
	Результат.Вставить("КодУчасткаИФНСФЛ", "");
	Результат.Вставить("КодУчасткаИФНСЮЛ", "");

	Возврат Результат;

КонецФункции

Функция КодКЛАДРСтрокой(Знач КодКЛАДР)

	КодКЛАДР = Формат(КодКЛАДР, "ЧГ=0");

	Если СтрДлина(КодКЛАДР) = 14 Тогда
		КодКЛАДР = "0" + КодКЛАДР + "00";
	ИначеЕсли СтрДлина(КодКЛАДР) = 15 Тогда
		КодКЛАДР = КодКЛАДР + "00"; // добавляем признак актуальности
	ИначеЕсли СтрДлина(КодКЛАДР) = 16 Тогда
		КодКЛАДР = "0" + КодКЛАДР;
	КонецЕсли;

	Возврат КодКЛАДР;

КонецФункции

Функция КодМуниципальногоРайона(Знач ТипМуниципальногоРайона, ОКТМО, ЭтоГородФедеральногоЗначения)

	КодМуниципальногоРайона = "";

	Если СтрДлина(ОКТМО) > 3 Тогда

		КодВторойСтупениКлассификации = Сред(ОКТМО, 3, 1);
		Если КодВторойСтупениКлассификации = "3" Или ЭтоГородФедеральногоЗначения И КодВторойСтупениКлассификации = "9" Тогда
			КодМуниципальногоРайона = "3";
		ИначеЕсли КодВторойСтупениКлассификации = "6" Тогда
			КодМуниципальногоРайона = "1";
		ИначеЕсли КодВторойСтупениКлассификации = "7" Тогда
			КодМуниципальногоРайона = "2";
		ИначеЕсли КодВторойСтупениКлассификации = "9" И Не ЭтоГородФедеральногоЗначения Тогда
			КодМуниципальногоРайона = "4";
		ИначеЕсли КодВторойСтупениКлассификации = "8" Тогда
			КодМуниципальногоРайона = "4";
		КонецЕсли;

	Иначе
		// АПК: 1297-выкл Данные адресного классификатора, не локализуются
		Если СтрСравнить(ТипМуниципальногоРайона, "м.р-н") = 0 Тогда
			КодМуниципальногоРайона = "1";
		ИначеЕсли СтрСравнить(ТипМуниципальногоРайона, "г.о.") = 0 Тогда
			КодМуниципальногоРайона = "2";
		ИначеЕсли СтрСравнить(ТипМуниципальногоРайона, "вн.тер.") = 0 
			  Или СтрСравнить(ТипМуниципальногоРайона, "вн.тер. г.") = 0 Тогда // @Non-NLS-1
				КодМуниципальногоРайона = "3";
		ИначеЕсли СтрСравнить(ТипМуниципальногоРайона, "мун. окр.") = 0 Тогда
			КодМуниципальногоРайона = "4";
		КонецЕсли;
		// АПК: 1297-вкл
	КонецЕсли;

	Возврат КодМуниципальногоРайона;

КонецФункции

Функция КодПоселения(Знач ТипПоселения)

	КодПоселения = "";
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Если СтрСравнить(ТипПоселения, "г. п.") = 0 Или СтрСравнить(ТипПоселения, "г.п.") = 0 Тогда // @Non-NLS-2
		КодПоселения = "1";
	ИначеЕсли СтрСравнить(ТипПоселения, "с.п.") = 0 Тогда
		КодПоселения = "2";
	ИначеЕсли СтрСравнить(ТипПоселения, "меж.тер.") = 0 Тогда
		КодПоселения = "3";
	ИначеЕсли СтрСравнить(ТипПоселения, "вн.р-н") = 0 Тогда
		КодПоселения = "4";
	КонецЕсли;
	// АПК: 1297-вкл
	Возврат КодПоселения;

КонецФункции

// Прочие 

// Заполнение адреса по данным сервиса 1С.
// 
Процедура ЗаполнитьАдресаПоПочтовомуИндексуКлассификатораСервис1С(Результат, Индекс)

	ТекстGETЗапроса = "selectByCode?code=%ZipCode%&codeType=POSTAL_CODE";
	ТекстGETЗапроса = СтрЗаменить(ТекстGETЗапроса, "%ZipCode%", Формат(Индекс, "ЧГ=0"));

	РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

	Если РезультатВебСервис.Отказ Тогда
		Возврат;
	КонецЕсли;

	Для Каждого СтрокаДанных Из РезультатВебСервис.Данные Цикл

		ПредставлениеТерриториальное = СтрокаДанных.valueReversed;
		ПредставлениеМуниципальное = СтрокаДанных.munValueReversed;

		Если ЗначениеЗаполнено(ПредставлениеМуниципальное) Тогда
			НоваяСтрока = Результат.Данные.Добавить();
			НоваяСтрока.Представление = ПредставлениеМуниципальное;
			НоваяСтрока.Муниципальный = Истина;
			НоваяСтрока.Идентификатор = СтрокаДанных.id;
		КонецЕсли;

		Если ПредставлениеТерриториальное <> ПредставлениеМуниципальное 
		   И ЗначениеЗаполнено(ПредставлениеТерриториальное) Тогда
			НоваяСтрока = Результат.Данные.Добавить();
			НоваяСтрока.Представление = ПредставлениеТерриториальное;
			НоваяСтрока.Муниципальный = Ложь;
			НоваяСтрока.Идентификатор = СтрокаДанных.id;
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

// Заполнение данных для проверки версии по сервису 1С.
// 
Процедура ЗаполнитьВерсиюПоставщикаДанныхСервис1С(Результат)

	РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис("ping", 7);

	Если РезультатВебСервис.Отказ Тогда
		Результат.Данные = Ложь;
	Иначе
		Результат.Данные = РезультатВебСервис.Данные;
	КонецЕсли;

КонецПроцедуры

// Заполнение данных для автоподбора по данным сервиса 1С.
// Пример: autocomplete?text=test&parentGuid=g-u-i-d&from=30&limit=15.
// 
Процедура ЗаполнитьСписокАвтоподбораЧастиАдресаСервис1С(ВариантыАдреса, КешПредставлений, Текст, Родитель, Количество,
	ДополнительныеПараметры)

	ТекстGETЗапроса = "autocomplete?text=" + КодироватьСтроку(Текст, СпособКодированияСтроки.КодировкаURL);
	Если ЗначениеЗаполнено(Родитель) Тогда
		ТекстGETЗапроса = ТекстGETЗапроса + "&parentGuid=" + Строка(Родитель);
	КонецЕсли;
	Если ЗначениеЗаполнено(Количество) Тогда
		ТекстGETЗапроса = ТекстGETЗапроса + "&limit=" + Формат(Количество, "ЧГ=0");
	КонецЕсли;

	Если ДополнительныеПараметры.Свойство("Уровни") Тогда
		ТекстGETЗапроса = ТекстGETЗапроса + "&levels=" + ДополнительныеПараметры.Уровни;
	КонецЕсли;

	РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);
	Если РезультатВебСервис.Отказ Или РезультатВебСервис.Количество() = 0 Или РезультатВебСервис.Данные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ДобавлятьМуниципальныеАдреса                  = Истина;
	ДобавлятьАдминистративноТерриториальныеАдреса = Истина;

	Если ЗначениеЗаполнено(ДополнительныеПараметры.ТипАдреса) Тогда
		ДобавлятьМуниципальныеАдреса = ЭтоМуниципальныйАдрес(ДополнительныеПараметры.ТипАдреса);
		ДобавлятьАдминистративноТерриториальныеАдреса = ЭтоАдминистративноТерриториальныйАдрес(
			ДополнительныеПараметры.ТипАдреса);
	КонецЕсли;

	Для Каждого Данные Из РезультатВебСервис.Данные Цикл

		Если ВариантыАдреса.Количество() >= 20 Тогда
			Возврат;
		КонецЕсли;
		ПредставлениеТерриториальное = Данные.valueReversed;
		ПредставлениеМуниципальное   = Данные.munValueReversed;

		Если ДобавлятьМуниципальныеАдреса И ЗначениеЗаполнено(Данные.munId) И ЗначениеЗаполнено(
			ПредставлениеМуниципальное) Тогда
			ДанныеМуниципальный = АдресДляСохраненияВБазе(Данные);

			Сведения = СведенияОПодбираемомАдресе(ПредставлениеМуниципальное, Данные.id, Истина, Ложь,
				СтруктураВСтрокуJSON(ДанныеМуниципальный));
			ДобавитьВариантАдреса(ВариантыАдреса, КешПредставлений, Сведения);
		КонецЕсли;

		Если ДобавлятьАдминистративноТерриториальныеАдреса И ЗначениеЗаполнено(ПредставлениеТерриториальное)
			И (Не ЗначениеЗаполнено(Данные.munId) Или СтрСравнить(ПредставлениеТерриториальное,
			ПредставлениеМуниципальное) <> 0) Тогда

			ДанныеТерриториальный = АдресДляСохраненияВБазе(Данные, Ложь);

			Сведения = СведенияОПодбираемомАдресе(ПредставлениеТерриториальное, Данные.id, Ложь, Ложь,
				СтруктураВСтрокуJSON(ДанныеТерриториальный));
			ДобавитьВариантАдреса(ВариантыАдреса, КешПредставлений, Сведения);

		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Процедура ДобавитьВариантАдреса(ВариантыАдреса, КешПредставлений, Сведения, ДобавитьВНачалоСписка = Ложь)
	
	// Такой адрес уже есть в списке выбора.
	Если КешПредставлений[ВРег(Сведения.Представление)] <> Неопределено Тогда
		Возврат;
	КонецЕсли;
	КешПредставлений[ВРег(Сведения.Представление)] = Истина;

	Если Не Сведения.Муниципальный Тогда
		Сведения.Представление = Новый ФорматированнаяСтрока(Сведения.Представление,,
			ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет);
	КонецЕсли;

	Если ДобавитьВНачалоСписка Тогда
		ВариантыАдреса.Вставить(0, Сведения, Сведения.Представление);
	Иначе
		ВариантыАдреса.Добавить(Сведения, Сведения.Представление);
	КонецЕсли;

КонецПроцедуры

Функция СведенияОПодбираемомАдресе(Знач Представление, Знач Идентификатор, Знач Муниципальный, Знач ЗагруженныеДанные,
	Знач Данные = Неопределено, ПредлагатьЗагрузкуКлассификатора = Ложь)

	Сведения = Новый Структура;
	Сведения.Вставить("Отказ", Ложь);
	Сведения.Вставить("Адрес", Данные);
	Сведения.Вставить("Идентификатор", Идентификатор);
	Сведения.Вставить("Представление", Представление);
	Сведения.Вставить("Муниципальный", Муниципальный);
	Сведения.Вставить("ЗагруженныеДанные", ЗагруженныеДанные);
	Сведения.Вставить("ПредлагатьЗагрузкуКлассификатора", ПредлагатьЗагрузкуКлассификатора);
	Возврат Сведения;

КонецФункции

// Заполнение актуальных данных адресного объекта или ориентира по данным сервиса 1С.
// Пример: GET /selectByCode?code=111111&codeType=ID.
//
Процедура ЗаполнитьАктуальныеАдресныеСведенияСервис1С(Результат, СведенияОбАдресномОбъекте, ЭтоМуниципальныйАдрес = Истина)

	Идентификатор = СведенияОбАдресномОбъекте.Идентификатор;
	
	РезультатВебСервис = АдресныеСведенияСервис1СПоКоду(Результат, Идентификатор, "ID");

	Если РезультатВебСервис.Отказ Или РезультатВебСервис.Данные.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если РезультатВебСервис.Данные.Количество() = 1 Тогда
		Результат.Данные = АдресДляСохраненияВБазе(РезультатВебСервис.Данные[0], ЭтоМуниципальныйАдрес);
	Иначе
		// Для городов содержащих несколько вн.р-н внутри города и нужно выбрать ранее введенный.
		ВыбранныйАдрес = РезультатВебСервис.Данные[0];
		
		Если ЗначениеЗаполнено(СведенияОбАдресномОбъекте.Адрес) Тогда
			Для каждого АдресИзВебСервиса Из РезультатВебСервис.Данные Цикл
				Если СтрСравнить(АдресИзВебСервиса.settlement, СведенияОбАдресномОбъекте.Адрес.settlement) = 0 
				   И СтрСравнить(АдресИзВебСервиса.settlementType, СведенияОбАдресномОбъекте.Адрес.settlementType) =0 Тогда
						ВыбранныйАдрес = АдресИзВебСервиса;
						Прервать;
				КонецЕсли; 
			КонецЦикла;
		КонецЕсли;
		
		Результат.Данные = АдресДляСохраненияВБазе(ВыбранныйАдрес, ЭтоМуниципальныйАдрес);
	КонецЕсли;
	
КонецПроцедуры

Функция АдресныеСведенияСервис1СПоКоду(Результат, Знач Идентификатор, Знач ИмяКода)
	
	ШаблонЗапроса = "selectByCode?code=%1&codeType=%2";
	ТекстGETЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗапроса,
		Строка(Идентификатор), ИмяКода);
	
	Возврат ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);
	
КонецФункции

// Получает идентификаторы адреса через веб-сервис.
//
// Параметры:
//  Результат - Структура:
//    * ИдентификаторАдресногоОбъекта - УникальныйИдентификатор - идентификатор адресного объекта (улицы, нас. пункта).
//    * ИдентификаторДома             - УникальныйИдентификатор - идентификатор дома адресного объекта.
//    * Отказ                         - Булево - поставщик не доступен.
//    * ПодробноеПредставлениеОшибки  - Строка - описание ошибки, если поставщик недоступен иначе Неопределено.
//    * КраткоеПредставлениеОшибки    - Строка - описание ошибки, если поставщик недоступен иначе Неопределено.
//  АдресДляПроверки - Строка - строка XML контактной информации содержащая адрес.
// 
Процедура ОпределитьИдентификаторыАдресаСервис1С(Результат, АдресДляПроверки)

	Если АдресныйКлассификаторПовтИсп.ИспользоватьТолькоЗагруженныеДанные() Тогда
		Возврат;
	КонецЕсли;
	
	Сервис = АдресныйКлассификаторПовтИсп.СервисКлассификатора1С();

	СписокДляПроверки = Сервис.ФабрикаXDTO.Создать(Сервис.ФабрикаXDTO.Тип(ПространствоИмен(), "AddressList"));
	ТипЭлементаСписка = СписокДляПроверки.Свойства().Получить("Item").Тип;

	СписокЭлементовДляПроверки =  СписокДляПроверки.Item; // СписокXDTO
	ПроверяемыйАдрес =  СписокЭлементовДляПроверки.Добавить(Сервис.ФабрикаXDTO.Создать(ТипЭлементаСписка));
	ПроверяемыйАдрес.Levels  = УровниКлассификатора();
	Если ЭтоКонтактнаяИнформацияВXML(АдресДляПроверки) Тогда
		АдресXDTO = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(АдресДляПроверки, Сервис.ФабрикаXDTO);
		ПроверяемыйАдрес.Address = АдресXDTO.Состав.Состав;
	Иначе
		ВызватьИсключение НСтр("ru = 'Сведения о контактной информации были повреждены или некорректно заполнены'");
	КонецЕсли;

	КодЯзыка = ТекущийКодЛокализации();
	РезультатПроверки = Сервис.Analyze(СписокДляПроверки, КодЯзыка, Ложь, Метаданные.Имя);
	
	// Формируем структуру результата.
	Если РезультатПроверки.Item.Количество() > 0 Тогда
		Если РезультатПроверки.Item[0].Error.Количество() > 0 Тогда
			Ошибка = РезультатПроверки.Item[0].Error[0];
			Результат.КраткоеПредставлениеОшибки = Ошибка.Text;
			Результат.ПодробноеПредставлениеОшибки = Ошибка.Suggestion;
			Результат.Отказ = Истина;
		КонецЕсли;

		Если РезультатПроверки.Item[0].Variant.Количество() Тогда
			Вариант = РезультатПроверки.Item[0].Variant[0];
			Результат.ИдентификаторАдресногоОбъекта = Вариант.ID;
			Результат.ИдентификаторДома = Вариант.HouseID;
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

// Заполнение результата проверки адресного объекта по данным сервиса.
// Выполнение запроса может занимать 20 секунд.
//
Функция ЗаполнитьРезультатПроверкиАдресаПоКлассификаторуСервис1С(Знач АдресаДляПроверки,
	ЭтоУстановкаИдентификаторов = Истина)

	Результат = РезультатИзВебСервиса();
	
	Если АдресныйКлассификаторПовтИсп.ИспользоватьТолькоЗагруженныеДанные() Тогда
		Возврат Результат;
	КонецЕсли;
	
	Сервис = АдресныйКлассификаторПовтИсп.СервисКлассификатора1С(20);

	ПрефиксВерсииЗапроса = ПрефиксВерсииЗапроса();

	HTTPЗапрос = Новый HTTPЗапрос(ПрефиксВерсииЗапроса + "verify");
	ИдентификаторЗапроса = Строка(Новый УникальныйИдентификатор);

	ДанныеЗапроса = Новый Массив;
	Для Каждого КлючЗначение Из АдресаДляПроверки Цикл

		Адрес = КлючЗначение.Значение;

		АдресДляПроверки = Новый Структура;
		АдресДляПроверки.Вставить("key", "_" + КлючЗначение.Ключ);
		АдресДляПроверки.Вставить("typeToVerify",    ТипАдресаДляВебСервиса(Адрес.addressType));
		АдресДляПроверки.Вставить("addressToVerify", АдресДляПередачиВСервис(Адрес));
		ДанныеЗапроса.Добавить(АдресДляПроверки);

	КонецЦикла;

	ДанныеДляЗапроса = Новый Структура("requests", ДанныеЗапроса);

	HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json");
	HTTPЗапрос.Заголовки.Вставить("X-1C-Request-UID", ИдентификаторЗапроса);
	HTTPЗапрос.УстановитьТелоИзСтроки(СтруктураВСтрокуJSON(ДанныеДляЗапроса));

	Попытка
		РезультатПроверки = Сервис.ОтправитьДляОбработки(HTTPЗапрос);
	Исключение

		Результат.Отказ = Истина;
		Результат.ПодробноеПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		Результат.КраткоеПредставлениеОшибки = НСтр("ru = 'При получении данных из веб-сервиса возникли проблемы.'");
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
			Результат.ПодробноеПредставлениеОшибки);
		Возврат Результат;
	КонецПопытки;

	Результат.Отказ  = Ложь;

	ПолученныеДанные = РезультатПроверки.ПолучитьТелоКакСтроку("UTF-8");

	Если РезультатПроверки.КодСостояния = 200 Тогда

		ДанныеПроверки = СтрокуJSONВСтруктуру(ПолученныеДанные);

	Иначе

		Если РезультатПроверки.КодСостояния = 400 Тогда

			ПредставлениеОшибки = 
				НСтр("ru = 'Проверка адреса не выполнена. Некоторые поля адреса содержат некорректные сведения.'");

		Иначе

			ПредставлениеОшибки = НСтр("ru = 'Проверка адреса не доступна по причине:
							|- не подключена интернет-поддержка пользователей;
							|- неполадки у интернет-провайдера;
							|- подключение к серверу блокирует межсетевой экран, 
							|  антивирусная программа или другое программное обеспечение;
							|- веб-сервис отключен или на техническом обслуживании.'");

		КонецЕсли;

		Результат.КраткоеПредставлениеОшибки   = ПредставлениеОшибки;
		Результат.ПодробноеПредставлениеОшибки = ПредставлениеОшибки;
		Результат.Отказ = Истина;

		ЗаписатьОшибкуЗапросаКВебСервисуВЖурналРегистрации(ПолученныеДанные, Результат, HTTPЗапрос.АдресРесурса
			+ " X-1C-Request-UID:" + ИдентификаторЗапроса, РезультатПроверки.КодСостояния);

		Возврат Результат;

	КонецЕсли;

	Если ДанныеПроверки = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	ОписаниеТипаЧисло = ОбщегоНазначения.ОписаниеТипаЧисло(10);

	Для Каждого Проверка Из ДанныеПроверки Цикл

		РезультатПроверки = РезультатПроверкиАдреса();
		ЭлементПроверки   = Проверка.Значение;
		УникальныйКлюч    = ОписаниеТипаЧисло.ПривестиЗначение(Сред(Проверка.Ключ, 2));

		Если ЭлементПроверки.Свойство("status") Тогда

			РезультатПроверки.АдресПроверен   = Истина;
			РезультатПроверки.АдресКорректный = (СтрСравнить(ЭлементПроверки.status, "COMPLETELY_VERIFIED") = 0);

			Если СтрСравнить(ЭлементПроверки.status, "HISTORIC") = 0 Тогда
				РезультатПроверки.АдресУстарел = Истина;
			КонецЕсли;

		КонецЕсли;

		Если ЭлементПроверки.Свойство("errorMessage") И ЗначениеЗаполнено(ЭлементПроверки.errorMessage) Тогда
			
			ОписаниеОшибки = НовоеОписаниеОшибки();
			ОписаниеОшибки.Ключ  = ЭлементПроверки.errorCode;
			ОписаниеОшибки.Текст = ЭлементПроверки.errorMessage;
			РезультатПроверки.Ошибки.Добавить(ОписаниеОшибки);
			
		КонецЕсли;

		Если ЭтоУстановкаИдентификаторов Или РезультатПроверки.АдресУстарел Тогда
			Если ЭлементПроверки.Свойство("value") И ЗначениеЗаполнено(ЭлементПроверки.value) Тогда
				Вариант = ОбщегоНазначения.СкопироватьРекурсивно(ЭлементПроверки.value); // Структура
				ШаблонКонтактнойИнформации = ОписаниеНовойКонтактнойИнформации();
				Для Каждого СвойствоСтруктуры Из Вариант Цикл
					Если ШаблонКонтактнойИнформации.Свойство(СвойствоСтруктуры.Ключ) 
						 И СвойствоСтруктуры.Значение = Неопределено Тогда
							Вариант[СвойствоСтруктуры.Ключ] = ШаблонКонтактнойИнформации[СвойствоСтруктуры.Ключ];
					КонецЕсли;
				КонецЦикла;
				Если Не Вариант.Свойство("addressType") Тогда
					Вариант.Вставить("addressType", Адрес.addressType);
				КонецЕсли;
				РезультатПроверки.Варианты.Добавить(Вариант);
			КонецЕсли;
		КонецЕсли;

		Результат.Данные.Вставить(УникальныйКлюч, РезультатПроверки);

	КонецЦикла;

	Возврат Результат;

КонецФункции

Функция ВерсияJSON(Адрес)
	
	ИмяСвойства = ?(ЭтоМуниципальныйАдрес(Адрес.AddressType), "munLevels", "admLevels");
	
	Если Адрес.Свойство(ИмяСвойства) И Адрес[ИмяСвойства].Количество() > 0 Тогда
		Возврат 4;
	КонецЕсли;
	
	Возврат 3;
	
КонецФункции

Функция НовоеОписаниеОшибки()
	
	ОписаниеОшибки = Новый Структура;
	
	ОписаниеОшибки.Вставить("Ключ",     "");
	ОписаниеОшибки.Вставить("Текст",    "");
	ОписаниеОшибки.Вставить("Подсказка", "");
	
	Возврат ОписаниеОшибки;
	
КонецФункции

Функция ТипАдресаДляВебСервиса(ТипАдреса)
	Возврат ?(ЭтоМуниципальныйАдрес(ТипАдреса), "MUNICIPAL", "ADMINISTRATIVE");
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Данные - Соответствие из КлючИЗначение:
//     ** Ключ - Число - идентификатор адреса
//     ** Значение - см. РезультатПроверкиАдреса
//   * КраткоеПредставлениеОшибки - Строка
//   * ПодробноеПредставлениеОшибки - Строка
//    * Отказ - Булево
//
Функция РезультатИзВебСервиса()

	Результат = Новый Структура;
	Результат.Вставить("Отказ", Ложь);
	Результат.Вставить("ПодробноеПредставлениеОшибки", "");
	Результат.Вставить("КраткоеПредставлениеОшибки", "");
	Результат.Вставить("Данные", Новый Соответствие);

	Возврат Результат;

КонецФункции

Функция ПредставлениеДомаИСтроений(ОписаниеДома)

	СписокСтроений = Новый Массив;
	Шаблон = "%1 ""%2""";

	Если ЗначениеЗаполнено(ОписаниеДома.НомерДома) Тогда
		СписокСтроений.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон,
			НРег(ОписаниеДома.НаименованиеДома), ОписаниеДома.НомерДома));
	КонецЕсли;

	Если ЗначениеЗаполнено(ОписаниеДома.ДополнительныйНомерДома1) Тогда
		СписокСтроений.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон,
			НРег(ОписаниеДома.НаименованиеДополнительногоДома1), ОписаниеДома.ДополнительныйНомерДома1));
	КонецЕсли;

	Если ЗначениеЗаполнено(ОписаниеДома.ДополнительныйНомерДома2) Тогда
		СписокСтроений.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон,
			НРег(ОписаниеДома.НаименованиеДополнительногоДома2), ОписаниеДома.ДополнительныйНомерДома2));
	КонецЕсли;

	Возврат СтрСоединить(СписокСтроений, ", ");

КонецФункции

Функция ДанныеУровняКорректные(Знач ИмяУровня, Знач АдресСтрока, Знач КакиеУровниПроверять)
	
	Если КакиеУровниПроверять[ИмяУровня] <> Неопределено 
	   И ПустаяСтрока(АдресСтрока["Наименование" + КакиеУровниПроверять[ИмяУровня]]) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция КонструкторКодовАдреса()

	Результат = Новый Структура;

	КодыКЛАДР = Новый Структура;
	КодыКЛАДР.Вставить("Регион");
	КодыКЛАДР.Вставить("Округ");
	КодыКЛАДР.Вставить("Район");
	КодыКЛАДР.Вставить("Город");
	КодыКЛАДР.Вставить("ВнутригородскойРайон");
	КодыКЛАДР.Вставить("НаселенныйПункт");
	КодыКЛАДР.Вставить("Улица");

	Результат.Вставить("КодыКЛАДР", КодыКЛАДР);

	Коды = Новый Структура;
	Коды.Вставить("КодКЛАДР",               "");
	Коды.Вставить("Идентификатор",          "");
	Коды.Вставить("ИдентификаторДома",      "");
	Коды.Вставить("ОКАТО",                  "");
	Коды.Вставить("ОКТМО",                  "");
	Коды.Вставить("ОКТМОБюджетополучателя", "");
	Коды.Вставить("КодИФНСФЛ",              "");
	Коды.Вставить("КодИФНСЮЛ",              "");
	Коды.Вставить("КодУчасткаИФНСФЛ",       "");
	Коды.Вставить("КодУчасткаИФНСЮЛ",       "");

	Результат.Вставить("КодыАдреса", Коды);

	Возврат Результат;

КонецФункции

Функция ПараметрыАутентификацииНаСайте() Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей") Тогда
		МодульИнтернетПоддержкаПользователей = ОбщегоНазначения.ОбщийМодуль("ИнтернетПоддержкаПользователей");
		Возврат МодульИнтернетПоддержкаПользователей.ДанныеАутентификацииПользователяИнтернетПоддержки();
	Иначе
		ВызватьИсключение НСтр("ru = 'Сервис интернет-поддержки пользователей не подключен.'");
	КонецЕсли;

КонецФункции

Функция ЗаполненыДанныеАутентификацииПользователяИнтернетПоддержки() Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей") Тогда
		МодульИнтернетПоддержкаПользователей = ОбщегоНазначения.ОбщийМодуль("ИнтернетПоддержкаПользователей");
		Возврат МодульИнтернетПоддержкаПользователей.ЗаполненыДанныеАутентификацииПользователяИнтернетПоддержки();
	КонецЕсли;

	Возврат Ложь;

КонецФункции

Процедура ДобавитьОшибкуПроверкиАдресаПоКлассификатору(ВсеОшибки, Ключ, Текст, Подсказка = Неопределено)

	Ошибка = Новый Структура("Ключ, Текст, Подсказка", Ключ, Текст, Подсказка);
	ВсеОшибки.Добавить(Ошибка);

КонецПроцедуры

// Десериализует объект из XML.
//
Функция ДесериализацияАдресаXDTO(Строка)

	ПередЧтениемXDTOКонтактнаяИнформация(Строка);

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(Строка);
	
	// ожидается пространство имен "http://www.v8.1c.ru/ssl/contactinfo_ru".
	Результат = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);

	Возврат Результат
КонецФункции

// Преобразует XML. Обратная совместимость.
//
Функция ПередЧтениемXDTOКонтактнаяИнформация(ТекстXML)

	Если СтрНайти(ТекстXML, "Адрес") = 0 Тогда
		Возврат ТекстXML;
	КонецЕсли;

	Если СтрНайти(ТекстXML, "http://www.v8.1c.ru/ssl/contactinfo_ru") > 0 Тогда
		Возврат ТекстXML;
	КонецЕсли;

	ТекстXML = СтрЗаменить(ТекстXML, "xsi:type=""АдресРФ""",
		"xmlns:rf=""http://www.v8.1c.ru/ssl/contactinfo_ru"" xsi:type=""rf:АдресРФ""");

	ТекстXML = СтрЗаменить(ТекстXML, "<СубъектРФ", "<rf:СубъектРФ");
	ТекстXML = СтрЗаменить(ТекстXML, "/СубъектРФ>", "/rf:СубъектРФ>");
	ТекстXML = СтрЗаменить(ТекстXML, "<СубъектРФ/>", "<rf:СубъектРФ/>");

	ТекстXML = СтрЗаменить(ТекстXML, "<Округ", "<rf:Округ");
	ТекстXML = СтрЗаменить(ТекстXML, "/Округ>", "/rf:Округ>");
	ТекстXML = СтрЗаменить(ТекстXML, "<Округ/>", "<rf:Округ/>");

	ТекстXML = СтрЗаменить(ТекстXML, "<СвРайМО", "<rf:СвРайМО");
	ТекстXML = СтрЗаменить(ТекстXML, "/СвРайМО>", "/rf:СвРайМО>");
	ТекстXML = СтрЗаменить(ТекстXML, "<СвРайМО/>", "<rf:СвРайМО/>");

	ТекстXML = СтрЗаменить(ТекстXML, "<Район", "<rf:Район");
	ТекстXML = СтрЗаменить(ТекстXML, "/Район>", "/rf:Район>");
	ТекстXML = СтрЗаменить(ТекстXML, "</Район>", "</rf:Район>");

	ТекстXML = СтрЗаменить(ТекстXML, "<Город", "<rf:Город");
	ТекстXML = СтрЗаменить(ТекстXML, "/Город>", "/rf:Город>");
	ТекстXML = СтрЗаменить(ТекстXML, "<Город/>", "<rf:Город/>");

	ТекстXML = СтрЗаменить(ТекстXML, "ВнутригРайон", "rf:ВнутригРайон");

	ТекстXML = СтрЗаменить(ТекстXML, "НаселПункт", "rf:НаселПункт");

	ТекстXML = СтрЗаменить(ТекстXML, "<Улица", "<rf:Улица");
	ТекстXML = СтрЗаменить(ТекстXML, "/Улица>", "/rf:Улица>");
	ТекстXML = СтрЗаменить(ТекстXML, "<Улица/>", "<rf:Улица/>");

	ТекстXML = СтрЗаменить(ТекстXML, "ОКТМО", "rf:ОКТМО");
	ТекстXML = СтрЗаменить(ТекстXML, "ОКАТО", "rf:ОКАТО");

	ТекстXML = СтрЗаменить(ТекстXML, "ДопАдрЭл", "rf:ДопАдрЭл");

	ТекстXML = СтрЗаменить(ТекстXML, "<Номер", "<rf:Номер");
	ТекстXML = СтрЗаменить(ТекстXML, "/Номер>", "/rf:Номер>");
	ТекстXML = СтрЗаменить(ТекстXML, "<Номер/>", "<rf:Номер/>");

	ТекстXML = СтрЗаменить(ТекстXML, "<Местоположение", "<rf:Местоположение");
	ТекстXML = СтрЗаменить(ТекстXML, "/Местоположение>", "/rf:Местоположение>");
	ТекстXML = СтрЗаменить(ТекстXML, "<Местоположение/>", "<rf:Местоположение/>");

	Возврат ТекстXML;

КонецФункции

// Определяет словарь наименований полей адреса в соответствии с уровнем.
//
Функция СловарьКлючейПолейАдресВСоответствииСУровнем()

	Словарь = Новый Соответствие;

	Словарь.Вставить(1, "area");
	Словарь.Вставить(2, "district");
	Словарь.Вставить(3, "munDistrict");
	Словарь.Вставить(4, "settlement");
	Словарь.Вставить(5, "city");
	Словарь.Вставить(6, "locality");
	Словарь.Вставить(7, "territory");
	Словарь.Вставить(8, "street");

	Возврат Словарь;

КонецФункции

Процедура ЗаполнитьПоляВСоответствииСУровнемАдреса(Адрес, Выборка, Суффикс,
			СловарьИменПолей, Муниципальный,ПорядокПолей)
	
	Если ЗначениеЗаполнено(Выборка["Наименование" + Суффикс]) Тогда
		
		Идентификатор = Выборка["Идентификатор" + Суффикс];
		ИмяУровня     = СловарьИменПолей[Выборка["Уровень" + Суффикс]];
		
		Если ИмяУровня = Неопределено Тогда
			Возврат;
		КонецЕсли;
		
		ПорядокПолей.Добавить(ИмяУровня);
		
		Адрес[ИмяУровня]          = Выборка["Наименование" + Суффикс];
		Адрес[ИмяУровня + "Type"] = Выборка["ТипОбъекта" + Суффикс];
		Адрес[ИмяУровня + "Id"]   = ?(ЗначениеЗаполнено(Идентификатор),
			Новый УникальныйИдентификатор(Идентификатор), "");
		Адрес.ID = Адрес[ИмяУровня + "Id"];
	
	КонецЕсли;
	
КонецПроцедуры

// Конструктор полей структуры для описания ошибок.
//
Функция СтруктураОписанияОшибкиПоставщика(Описание = Неопределено, ИнформацияОбОшибке = Неопределено)

	Если Описание = Неопределено Тогда
		Описание = Новый Структура;
	КонецЕсли;

	Описание.Вставить("Отказ", ИнформацияОбОшибке <> Неопределено);
	Описание.Вставить("ПодробноеПредставлениеОшибки");
	Описание.Вставить("КраткоеПредставлениеОшибки");

	Если ИнформацияОбОшибке = Неопределено Тогда
		Описание.ПодробноеПредставлениеОшибки = НСтр("ru = 'Информация об ошибке отсутствует'");
		Возврат Описание;
	КонецЕсли;

	Описание.ПодробноеПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
	Текст = СокрЛП(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));

	Если ТипЗнч(ИнформацияОбОшибке.Причина) = Тип("ИнформацияОбОшибке") Тогда
		Если ИнформацияОбОшибке.Причина.Причина <> Неопределено Тогда
			ОписаниеОшибкиДляПоиска = ВРег(ИнформацияОбОшибке.Причина.Причина.Описание);
			ПозицияНачало = СтрНайти(ОписаниеОшибкиДляПоиска, "<FAULTSTRING>");
			Если ПозицияНачало > 0 Тогда
				ПозицияОкончание = СтрНайти(ОписаниеОшибкиДляПоиска, "</FAULTSTRING>");
				Текст = Сред(ИнформацияОбОшибке.Причина.Причина.Описание,
					ПозицияНачало + 13, ПозицияОкончание - ПозицияНачало - 13);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	// Отрезаем клиентский текст
	Позиция = СтрНайти(Текст, ": ");
	Если Позиция > 0 Тогда
		Текст = СокрЛ(Сред(СтрЗаменить(Текст, Символы.ПС, ""), Позиция + 1));
	КонецЕсли;
	
	// Отрезаем серверный текст
	Пока Истина Цикл
		Позиция = СтрНайти(Текст, "}:");
		Если Позиция = 0 Тогда
			Прервать;
		КонецЕсли;
		Текст = СокрЛ(Сред(Текст, Позиция + 2));
	КонецЦикла;

	Описание.КраткоеПредставлениеОшибки = Текст;
	Возврат Описание;
КонецФункции

Процедура ОбработатьОбщепринятыеСокращения(ДоступныеУровни)

	ОбщепринятыеСокращения = Новый Соответствие;
	ОбщепринятыеСокращения.Вставить("КОРП", "Корпус");
	ОбщепринятыеСокращения.Вставить("КОРП.", "Корпус");
	ОбщепринятыеСокращения.Вставить("К.", "Корпус");
	ОбщепринятыеСокращения.Вставить("КВ.", "Квартира");
	ОбщепринятыеСокращения.Вставить("КВ", "Квартира");
	ОбщепринятыеСокращения.Вставить("ОФ.", "Офис");
	ОбщепринятыеСокращения.Вставить("ОФ.", "Офис");
	ОбщепринятыеСокращения.Вставить("ПОМЕЩ", "Помещение");
	ОбщепринятыеСокращения.Вставить("ПОМЕЩ.", "Помещение");
	ОбщепринятыеСокращения.Вставить("Д", "Дом");
	ОбщепринятыеСокращения.Вставить("Д.", "Дом");
	ОбщепринятыеСокращения.Вставить("СТР.", "Строение");
	ОбщепринятыеСокращения.Вставить("ЛИТЕР", "Литера");

	Фильтр = Новый Структура("Уровень", 0);
	НераспознанныеСтроки = ДоступныеУровни.НайтиСтроки(Фильтр);
	Для Каждого НераспознаннаяЧастьАдреса Из НераспознанныеСтроки Цикл
		Если (ВРЕГ(НераспознаннаяЧастьАдреса.Наименование) = "МОСКВА"
		   Или ВРЕГ(НераспознаннаяЧастьАдреса.Наименование) = "САНКТ-ПЕТЕРБУРГ")
		   И ПустаяСтрока(НераспознаннаяЧастьАдреса.ТипОбъекта) Тогда
			
			НераспознаннаяЧастьАдреса.ТипОбъекта = "г";
			НераспознаннаяЧастьАдреса.Значение   = СоединитьНаименованиеИТипАдресногоОбъекта(
				НераспознаннаяЧастьАдреса.Наименование, НераспознаннаяЧастьАдреса.ТипОбъекта, Истина);
			
		Иначе

			ТипОбъекта = ОбщепринятыеСокращения[ВРЕГ(НераспознаннаяЧастьАдреса.ТипОбъекта)];
			Если ТипОбъекта <> Неопределено Тогда
				НераспознаннаяЧастьАдреса.ТипОбъекта = ТипОбъекта;
			КонецЕсли;

		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Функция ПерваяБукваЗаглавная(Строка)
	Возврат ВРег(Лев(Строка, 1)) + Сред(НРег(Строка), 2); // Использовать ТРег нельзя.
КонецФункции

#Область ПреобразованиеТиповДанныхАдресногоКлассификатора

// Преобразует ДвоичныеДанные в УникальныйИдентификатор.
// Выполняет обратное действие для функции УникальныйИдентификаторВДвоичныеДанные.
// 
// Параметры:
//     ДвоичныеДанные - ДвоичныеДанные - исходные данные.
//
// Возвращаемое значение:
//     УникальныйИдентификатор - результат преобразования.
//
Функция УникальныйИдентификаторИзДвоичныхДанных(ДвоичныеДанные) 
	
	// Двоичные -> hex
	ТипXDTOДвоичныеДанные = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "hexBinary");
	ЗначениеHEX = ФабрикаXDTO.Создать(ТипXDTOДвоичныеДанные, ДвоичныеДанные);
	
	// hex -> UUID
	СтрокаУИД = ЗначениеHEX.ЛексическоеЗначение;
	Возврат Новый УникальныйИдентификатор(Сред(СтрокаУИД, 1, 8) + "-" + Сред(СтрокаУИД, 9, 4) + "-" 
		+ Сред(СтрокаУИД, 13, 4) + "-" + Сред(СтрокаУИД, 17, 4) + "-" + Сред(СтрокаУИД, 21));
	
КонецФункции

// Преобразует строку base64 в УникальныйИдентификатор.
//
// Параметры:
//    Строка - Строка - регистрозависимые исходные данные.
//
// Возвращаемое значение:
//   УникальныйИдентификатор - возвращаемый идентификатор зависит от регистра букв, передавай строки.
//
Функция УникальныйИдентификаторИзСтроки64(Строка)

	Возврат УникальныйИдентификаторИзДвоичныхДанных( ДвоичныеДанныеИзСтроки(Строка));

КонецФункции

// Преобразует строку в ДвоичныеДанные.
// 
// Параметры:
//    Строка - Строка - исходные данные.
//
// Возвращаемое значение:
//     ДвоичныеДанные - результат преобразования.
//
Функция ДвоичныеДанныеИзСтроки(Строка)

	Возврат XMLЗначение(Тип("ДвоичныеДанные"), Строка);

КонецФункции

#КонецОбласти

#Область ПереносУстаревшегоКлассификатора

Функция ЗагруженыРегионыУстаревшегоКлассификатора()
	
	Если ПравоДоступа("Изменение", Метаданные.РегистрыСведений.АдресныеОбъекты) Тогда

		УстановитьПривилегированныйРежим(Истина);
		
		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ЗагруженныеВерсииАдресныхСведений.КодСубъектаРФ КАК КодСубъектаРФ
		|ИЗ
		|	РегистрСведений.ЗагруженныеВерсииАдресныхСведений КАК ЗагруженныеВерсииАдресныхСведений
		|ГДЕ
		|	ЗагруженныеВерсииАдресныхСведений.Версия < 1000";
		
		РезультатЗапроса = Запрос.Выполнить();
		
		Возврат Не РезультатЗапроса.Пустой();
		
	КонецЕсли;

	Возврат Ложь;

КонецФункции

// Проверяет есть ли хоть одна запись КЛАДР (исключая записи о регионах) требующая переноса.
//
Функция УстаревшийКлассификаторСодержитСведения()

	Если ПравоДоступа("Изменение", Метаданные.РегистрыСведений.АдресныеОбъекты) Тогда

		УстановитьПривилегированныйРежим(Истина);

		Если ПустаяСтрока(Константы.ИсточникДанныхАдресногоКлассификатора.Получить()) Тогда
			Возврат Истина;
		КонецЕсли;

	КонецЕсли;

	Возврат Ложь;

КонецФункции

#КонецОбласти

#Область ПрочиеСлужебныеПроцедурыИФункции

// Имя событие для записи в журнал регистрации.
// 
// Возвращаемое значение:
//  Строка - событие журнала регистрации
//
Функция СобытиеЖурналаРегистрации() Экспорт

	Возврат НСтр("ru = 'Адресный классификатор'", ОбщегоНазначения.КодОсновногоЯзыка());

КонецФункции

// Разделяет исходный текст на наименование и тип адресного объекта.
//
// Параметры:
//     Название - Строка - полное название, например "Москва г".
//     ЭтоРегион - Булево - признак, что в названии содержится наименование региона.
//
// Возвращаемое значение:
//     Структура:
//       * Наименование - Строка - наименование, например "Москва". Если тип объекта выделить не удалось, то исходное название.
//       * ТипОбъекта   - Строка - тип объекта, например "г". Если тип объекта выделить не удалось, то пустая строка.
//
Функция НаименованиеИТипОбъекта(Название, ЭтоРегион = Ложь) Экспорт

	Результат = НовыйНаименованиеИТипОбъекта();

	ТекстПоиска = СокрП(Название);

	Если ЭтоРегион И НаименованиеРегионаБезТипа(Название) Тогда

		Результат.Наименование = Название;
		Возврат Результат;

	КонецЕсли;
	
	ТекстВерхнийРегистр = ВРег(ТекстПоиска);
	Если СтрЗаканчиваетсяНа(ТекстВерхнийРегистр, "ТЕР. СНТ") Или СтрЗаканчиваетсяНа(ТекстВерхнийРегистр, "ТЕР. ДНТ") Тогда
		Результат.ТипОбъекта = Прав(Название, 8);
		Результат.Наименование = Лев(Название, СтрДлина(Название) - 9);
		Возврат Результат;
	КонецЕсли;

	Позиция = СтрДлина(ТекстПоиска);
	Пока Позиция > 0 Цикл
		Если ПустаяСтрока(Сред(ТекстПоиска, Позиция, 1)) Тогда
			Прервать;
		КонецЕсли;
		Позиция = Позиция - 1;
	КонецЦикла;

	Если Позиция = 0 Тогда
		Результат.Наименование = ТекстПоиска;
		Результат.ТипОбъекта   = "";
	Иначе
		Результат.Наименование = СокрП(Лев(ТекстПоиска, Позиция));
		Результат.ТипОбъекта   = Сред(ТекстПоиска, Позиция + 1);
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Наименование - Строка
//   * ТипОбъекта   - Строка
//
Функция НовыйНаименованиеИТипОбъекта()

	Результат = Новый Структура;
	Результат.Вставить("Наименование", "");
	Результат.Вставить("ТипОбъекта", "");
	Возврат Результат;

КонецФункции

// Набор уровней для запросов адресного классификатора.
//
// Возвращаемое значение:
//     ФиксированныйМассив - набор числовых уровней.
//
Функция УровниКлассификатора()

	Уровни = Новый Массив;
	Уровни.Добавить(1);
	Уровни.Добавить(2);
	Уровни.Добавить(3);
	Уровни.Добавить(5);
	Уровни.Добавить(4);
	Уровни.Добавить(6);
	Уровни.Добавить(7);
	Уровни.Добавить(8);

	Возврат Новый ФиксированныйМассив(Уровни);
КонецФункции

Функция ЭтоМуниципальныйАдрес(ТипАдреса)
	Возврат СтрСравнить(ТипАдреса, МуниципальныйАдрес()) = 0;
КонецФункции

Функция ЭтоАдминистративноТерриториальныйАдрес(ТипАдреса)
	Возврат СтрСравнить(ТипАдреса, АдминистративноТерриториальныйАдрес()) = 0;
КонецФункции

Функция ИменаУровнейАдреса(Адрес, ВключатьУлицу, ИсключатьУровеньДома = Ложь)

	ТипАдреса = Адрес.AddressType;
	ЭтоМуниципальныйАдрес = ЭтоМуниципальныйАдрес(ТипАдреса);
	
	УровниИзАдреса = ?(ЭтоМуниципальныйАдрес, Адрес.munLevels, Адрес.admLevels);
	
	Если ТипЗнч(УровниИзАдреса) = Тип("Массив") И УровниИзАдреса.Количество() > 0 Тогда
		
		Уровни = Новый Массив(Новый ФиксированныйМассив(УровниИзАдреса));
		
		Если Не ВключатьУлицу Тогда
			Позиция = Уровни.Найти("street");
			Если Позиция <> Неопределено Тогда
				Уровни.Удалить(Позиция);
			КонецЕсли;
		КонецЕсли;
		
		Если ИсключатьУровеньДома Тогда
			
			Позиция = Уровни.Найти("house");
			Если Позиция <> Неопределено Тогда
				Уровни.Удалить(Позиция);
			КонецЕсли;
			
			Позиция = Уровни.Найти("stead");
			Если Позиция <> Неопределено Тогда
				Уровни.Удалить(Позиция);
			КонецЕсли;
			
		КонецЕсли;
		
		ДопустимыеУровни = АдресныйКлассификаторПовтИсп.НомераУровнейАдресаПоНаименованию();
		
		Для Позиция = -Уровни.ВГраница() По 0 Цикл
			Если ТипЗнч(Уровни[-Позиция]) <> Тип("Строка") 
				 Или Не ДопустимыеУровни.Свойство(Строка(Уровни[-Позиция])) Тогда
					Уровни.Удалить(-Позиция);
			КонецЕсли;
		КонецЦикла;
		
		Возврат Уровни;
		
	КонецЕсли;
	
	Уровни = Новый Массив;
	
	Уровни.Добавить("area");
	Если ТипАдреса = "ЕАЭС" Тогда

		Уровни.Добавить("district");
		Уровни.Добавить("city");
		Уровни.Добавить("locality");

	Иначе

		Если ЭтоМуниципальныйАдрес(ТипАдреса) Тогда
			Уровни.Добавить("munDistrict");
			Уровни.Добавить("settlement");
		Иначе
			Уровни.Добавить("district");
			
		КонецЕсли;

		Уровни.Добавить("city");
		Уровни.Добавить("locality");
		Уровни.Добавить("territory");

		Если ВключатьУлицу Тогда
			Уровни.Добавить("street");
		КонецЕсли;

	КонецЕсли;

	Возврат Уровни;

КонецФункции

Функция ОсновнаяСтрана()
	Возврат "Россия";
КонецФункции

Функция ПрефиксВерсииЗапроса() Экспорт
	Возврат "rest/v4/";
КонецФункции

// Возвращает информацию из классификатора субъектов РФ.
//
// Возвращаемое значение:
//     ТаблицаЗначений - поставляемые данные. Колонки:
//       * КодСубъектаРФ  - Число  - код классификатора субъекта, например 77 для Москвы.
//       * Наименование   - Строка - наименование субъекта по классификатору. Например "Московская".
//       * ТипОбъекта     - Строка - наименование субъекта по классификатору. Например "Обл".
//       * ПочтовыйИндекс - Число  - индекс региона. Если 0 - то неопределено.
//       * ПочтовыйИндекс - Число  - индекс региона. Если 0 - то неопределено.
//       * Идентификатор  - УникальныйИдентификатор - идентификатор адресного объекта.
//
Функция СведенияОСубъектахРФ()
	Возврат РегистрыСведений.АдресныеОбъекты.КлассификаторСубъектовРФ();
КонецФункции

Функция ПредставлениеРегиона(Наименование, ТипОбъекта)

	Если СтрСравнить(ТипОбъекта, "Респ") = 0 Тогда
		Возврат СоединитьНаименованиеИТипАдресногоОбъекта(Наименование, "Республика");
	ИначеЕсли СтрСравнить(ТипОбъекта, "обл") = 0 Тогда
		Возврат СоединитьНаименованиеИТипАдресногоОбъекта(Наименование, "область", Истина);
	ИначеЕсли СтрСравнить(ТипОбъекта, "г") = 0 Тогда
		Возврат СоединитьНаименованиеИТипАдресногоОбъекта("г.", Наименование);
	КонецЕсли;

	Возврат СоединитьНаименованиеИТипАдресногоОбъекта(Наименование, ТипОбъекта, Истина);

КонецФункции

// Извлекает список домов полученного из регистра сведения описания и добавляет их в список значений.
//
// Параметры:
//  СтрокаСоСпискомДомов - Строка - описание списка домов из  регистра сведения.
//  СтрокаПоиска		 - Строка - строка отбора.
//  ВариантыДомов		 - СписокЗначений - список домов.
//
Процедура ИзвлечьСписокДомов(СтрокаСоСпискомДомов, СтрокаПоиска, ВариантыДомов, Запись, ТочноеСовпадение)

	ТипЧисло = Новый ОписаниеТипов("Число");
	МассивДомов = СтрРазделить(СтрокаСоСпискомДомов, Символы.ПС, Ложь);

	НаименованиеДомов = АдресныйКлассификаторПовтИсп.НаименованияВладенийИСтроений();

	Для Каждого Дом Из МассивДомов Цикл
		НомерДома = СтрРазделить(Сред(Дом, 25), Символы.Таб, Истина);

		ОписаниеДома = ОписаниеДомаИЗемельногоУчастка();
		ОписаниеДома.ИдентификаторДома = УникальныйИдентификаторИзСтроки64(Лев(Дом, 24));
		Если ЗначениеЗаполнено(НомерДома[0]) Тогда

			ТипИНомерДома = СтрРазделить(НомерДома[0], Символы.НПП);
			ОписаниеДома.ТипДома      = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
			ОписаниеДома.НомерДома = ТипИНомерДома[1];
			ДомЧислом = ТипИНомерДома[0] + Формат(НомерДомаЧислом(ОписаниеДома.НомерДома), "ЧЦ=4; ЧН=; ЧВН=; ЧГ=0;");
			Если ЗначениеЗаполнено(ОписаниеДома.ТипДома) Тогда
				ОписаниеДома.НаименованиеДома = НаименованиеДомов.Владения.Получить(ОписаниеДома.ТипДома);
			КонецЕсли;

		Иначе
			ДомЧислом = "10000";
		КонецЕсли;

		ОписаниеДома.Индекс           = Формат(Запись.ПочтовыйИндекс, "ЧГ=0");
		ОписаниеДома.ОКТМО            = Формат(Запись.ОКТМО, "ЧГ=0");
		ОписаниеДома.ОКАТО            = Формат(Запись.ОКАТО, "ЧГ=0");
		ОписаниеДома.КодИФНСФЛ        = Формат(Запись.КодИФНСФЛ, "ЧГ=0");
		ОписаниеДома.КодИФНСЮЛ        = Формат(Запись.КодИФНСЮЛ, "ЧГ=0");
		ОписаниеДома.КодУчасткаИФНСФЛ = Формат(Запись.КодУчасткаИФНСФЛ, "ЧГ=0");
		ОписаниеДома.КодУчасткаИФНСЮЛ = Формат(Запись.КодУчасткаИФНСЮЛ, "ЧГ=0");
		ОписаниеДома.КодКЛАДР         = Формат(Запись.КодКЛАДР, "ЧГ=0");
		ОписаниеДома.ЗагруженныеДанные = Истина;

		Если НомерДома.Количество() > 1 Тогда

			ТипИНомерДома = СтрРазделить(НомерДома[1], Символы.НПП);
			ОписаниеДома.ДополнительныйТипДома1   = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
			ОписаниеДома.ДополнительныйНомерДома1 = ТипИНомерДома[1];
			ОписаниеДома.НаименованиеДополнительногоДома1 = НаименованиеДомов.Строения.Получить(
				ОписаниеДома.ДополнительныйТипДома1);
			ДомЧислом1 = ТипИНомерДома[0] + Формат(НомерДомаЧислом(ТипИНомерДома[1]), "ЧЦ=4; ЧН=; ЧВН=; ЧГ=0;");
		Иначе
			ДомЧислом1 = "00000";
		КонецЕсли;

		Если НомерДома.Количество() > 2 Тогда

			ТипИНомерДома = СтрРазделить(НомерДома[2], Символы.НПП);
			ОписаниеДома.ДополнительныйТипДома2   = ТипЧисло.ПривестиЗначение(ТипИНомерДома[0]);
			ОписаниеДома.ДополнительныйНомерДома2 = ТипИНомерДома[1];
			ОписаниеДома.НаименованиеДополнительногоДома2 = НаименованиеДомов.Строения.Получить(
				ОписаниеДома.ДополнительныйТипДома2);
			ДомЧислом2 = ТипИНомерДома[0] + Формат(НомерДомаЧислом(ТипИНомерДома[1]), "ЧЦ=4; ЧН=; ЧВН=; ЧГ=0;");

		Иначе
			ДомЧислом2 = "00000";
		КонецЕсли;

		ОписаниеДома.ДомЧислом = ТипЧисло.ПривестиЗначение(ДомЧислом + ДомЧислом1 + ДомЧислом2);

		Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
			Если ТочноеСовпадение Тогда
				Если СтрСравнить(ОписаниеДома.НомерДома, СтрокаПоиска) = 0
				   Или СтрСравнить(ОписаниеДома.ДополнительныйНомерДома1, СтрокаПоиска) = 0
				   Или СтрСравнить(ОписаниеДома.ДополнительныйНомерДома2, СтрокаПоиска) = 0 Тогда
					ДобавитьИнформациюОДоме(ВариантыДомов, ОписаниеДома, НаименованиеДомов, СтрокаПоиска);
				КонецЕсли;
			Иначе
				Если СтрНачинаетсяС(ОписаниеДома.НомерДома, СтрокаПоиска)
				   Или СтрНачинаетсяС(ОписаниеДома.ДополнительныйНомерДома1, СтрокаПоиска)
				   Или СтрНачинаетсяС(ОписаниеДома.ДополнительныйНомерДома2, СтрокаПоиска) Тогда
					ДобавитьИнформациюОДоме(ВариантыДомов, ОписаниеДома, НаименованиеДомов, СтрокаПоиска);
				КонецЕсли;
			КонецЕсли;
		Иначе
			ДобавитьИнформациюОДоме(ВариантыДомов, ОписаниеДома, НаименованиеДомов);
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * НомерДома - Строка
//   * НаименованиеДома - Строка
//   * ДополнительныйНомерДома1 - Строка
//   * НаименованиеДополнительногоДома1 - Строка
//   * ДополнительныйНомерДома2 - Строка
//   * НаименованиеДополнительногоДома2 - Строка
//
Функция СведенияОДоме()

	СведенияОДоме = Новый Структура;

	СведенияОДоме.Вставить("НомерДома", "");
	СведенияОДоме.Вставить("НаименованиеДома", "");
	СведенияОДоме.Вставить("ДополнительныйНомерДома1", "");
	СведенияОДоме.Вставить("НаименованиеДополнительногоДома1", "");
	СведенияОДоме.Вставить("ДополнительныйНомерДома2", "");
	СведенияОДоме.Вставить("НаименованиеДополнительногоДома2", "");

	Возврат СведенияОДоме;

КонецФункции

// Возвращаемое значение:
//  Структура:
//    * ДомЧислом - Число
//    * НомерДома - Строка
//    * ДополнительныйНомерДома1 - Строка
//    * ДополнительныйНомерДома2 - Строка
//    * ТипДома - Число
//    * ДополнительныйТипДома1 - Число
//    * ДополнительныйТипДома2 - Число
//    * НаименованиеДома - Строка
//    * НаименованиеДополнительногоДома1 - Строка
//    * НаименованиеДополнительногоДома2 - Строка
//    * ИдентификаторДома - Неопределено, УникальныйИдентификатор
//    * Индекс - Строка
//    * ОКТМО - Строка
//    * ОКАТО - Строка
//    * КодИФНСФЛ - Строка
//    * КодИФНСЮЛ - Строка
//    * КодУчасткаИФНСФЛ - Строка
//    * КодУчасткаИФНСЮЛ - Строка
//    * КодКЛАДР - Строка
//    * ЗагруженныеДанные - Булево
//
Функция ОписаниеДомаИЗемельногоУчастка() Экспорт

	ОписаниеДома = СведенияОДоме();

	ОписаниеДома.Вставить("ДополнительныйТипДома1", 0);
	ОписаниеДома.Вставить("ДополнительныйТипДома2", 0);
	ОписаниеДома.Вставить("ТипДома",                0);
	ОписаниеДома.Вставить("ДомЧислом",              0);
	ОписаниеДома.Вставить("ИдентификаторДома",      Неопределено);
	ОписаниеДома.Вставить("Индекс",                 "");
	ОписаниеДома.Вставить("ОКТМО",                  "");
	ОписаниеДома.Вставить("ОКАТО",                  "");
	ОписаниеДома.Вставить("КодИФНСФЛ",              "");
	ОписаниеДома.Вставить("КодИФНСЮЛ",              "");
	ОписаниеДома.Вставить("КодУчасткаИФНСФЛ",       "");
	ОписаниеДома.Вставить("КодУчасткаИФНСЮЛ",       "");
	ОписаниеДома.Вставить("КодКЛАДР",               "");
	ОписаниеДома.Вставить("ЗагруженныеДанные",      Ложь);

	Возврат ОписаниеДома;

КонецФункции

Процедура ДобавитьИнформациюОДоме(ВариантыДомов, ОписаниеДома, НаименованиеЗданийИСтроений, СтрокаПоиска = "")

	Набор = Новый Массив;
	Набор.Добавить(СокрЛП(Строка(ОписаниеДома.НаименованиеДома) + " " + Строка(ОписаниеДома.НомерДома)));

	Если ЗначениеЗаполнено(ОписаниеДома.ДополнительныйНомерДома1) Тогда
		ДополнительныйДом1 = СокрЛП(Строка(ОписаниеДома.НаименованиеДополнительногоДома1) + " " + Строка(ОписаниеДома.ДополнительныйНомерДома1));
		Набор.Добавить(ДополнительныйДом1);
	КонецЕсли;

	Если ЗначениеЗаполнено(ОписаниеДома.ДополнительныйНомерДома2) Тогда
		ДополнительныйДом2 = СокрЛП(Строка(ОписаниеДома.НаименованиеДополнительногоДома2) + " " + Строка(ОписаниеДома.ДополнительныйНомерДома2));
		Набор.Добавить(ДополнительныйДом2);
	КонецЕсли;

	Представление = СтрСоединить(Набор, ", ");
	Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
		ПредставлениеСВыделением = СтрНайтиИВыделитьОформлением(Представление, СтрокаПоиска);
		Если ПредставлениеСВыделением <> Неопределено Тогда
			Представление = ПредставлениеСВыделением;
		КонецЕсли;
	КонецЕсли;
	
	ИнформацияОДоме = ВариантыДомов.Добавить();
	ИнформацияОДоме.Дом                = ОписаниеДома.НомерДома;
	ИнформацияОДоме.ДомЧислом          = ОписаниеДома.ДомЧислом;
	ИнформацияОДоме.ДополнительныйДом1 = ОписаниеДома.ДополнительныйНомерДома1;
	ИнформацияОДоме.ДополнительныйДом2 = ОписаниеДома.ДополнительныйНомерДома2;
	ИнформацияОДоме.Идентификатор      = ОписаниеДома.ИдентификаторДома;
	ИнформацияОДоме.Значение           = ОписаниеДома;
	ИнформацияОДоме.Представление      = Представление;
	
КонецПроцедуры

Функция НомерДомаЧислом(ИсходнаяСтрока)

	ИтоговоеЧисло = "0";
	Для Позиция = 1 По СтрДлина(ИсходнаяСтрока) Цикл
		Символ = Сред(ИсходнаяСтрока, Позиция, 1);
		Если СтрНайти("0123456789", Символ) > 0 Тогда
			ИтоговоеЧисло = ИтоговоеЧисло + Символ;
		Иначе
			ИтоговоеЧисло = ИтоговоеЧисло + "9";
			Прервать;
		КонецЕсли;
	КонецЦикла;

	Возврат Число(ИтоговоеЧисло);
	
КонецФункции

Функция КодыДомовВладенийИСтроений()
	
	Результат = Новый Структура("Дома, Строения", Новый Соответствие, Новый Соответствие);
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	СлужебныеАдресныеСведения.Тип КАК Тип,
	|	СлужебныеАдресныеСведения.Идентификатор КАК Идентификатор,
	|	СлужебныеАдресныеСведения.Ключ КАК Ключ,
	|	СлужебныеАдресныеСведения.Значение КАК Значение
	|ИЗ
	|	РегистрСведений.СлужебныеАдресныеСведения КАК СлужебныеАдресныеСведения
	|ГДЕ
	|	(СлужебныеАдресныеСведения.Тип = ""ТипыВладений""
	|			ИЛИ СлужебныеАдресныеСведения.Тип = ""ТипыСтроений"")
	|	И СлужебныеАдресныеСведения.Идентификатор > 0";
	
	РезультатЗапроса = Запрос.Выполнить().Выбрать();
	
	Пока РезультатЗапроса.Следующий() Цикл
		Если РезультатЗапроса.Тип = "ТипыВладений" Тогда
			Результат.Дома.Вставить(ВРег(РезультатЗапроса.Значение), РезультатЗапроса.Идентификатор);
		ИначеЕсли РезультатЗапроса.Тип = "ТипыСтроений" Тогда
			Результат.Строения.Вставить(ВРег(РезультатЗапроса.Значение), РезультатЗапроса.Идентификатор);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Путь к файлу на веб сервере, содержащему информацию по версиям адресных сведений.
//
// Возвращаемое значение:
//     Строка - путь к файлу описания данных.
//
Функция АдресФайлаОписанияДоступныхВерсий()

	Возврат "http://downloads.1c.ru/ipp/ITSREPV/V8Update/gar/version.zip";

КонецФункции

// Путь к веб сервису контактной информации
//
// Возвращаемое значение:
//     Строка - путь к файлу описания данных.
//
Функция АдресВебСервисаКонтактнойИнформации() Экспорт

	Возврат "https://api.orgaddress.1c.ru";

КонецФункции

// Пространство имен для операций XDTO.
//
// Возвращаемое значение:
//     Строка
//
Функция ПространствоИмен()

	Возврат "http://www.v8.1c.ru/ssl/AddressSystem";

КонецФункции


// Возвращает признак того, является ли строка данных контактной информации XML данными.
//
// Параметры:
//     Текст - Строка - проверяемая строка.
//
// Возвращаемое значение:
//     Булево - результат проверки.
//
Функция ЭтоКонтактнаяИнформацияВJSON(Знач Текст)

	Возврат ТипЗнч(Текст) = Тип("Строка") И СтрНачинаетсяС(СокрЛ(Текст), "{");

КонецФункции

// Обратная совместимость
//
Функция ИсправлениеСокращений(ТипОбъекта)
	
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Если СтрСравнить(ТипОбъекта, "г. п.") = 0 Тогда
		Возврат "г.п.";
	КонецЕсли;

	Если СтрСравнить(ТипОбъекта, "вн.тер") = 0 Или СтрСравнить(ТипОбъекта, "вн.тер.") = 0 Тогда
		Возврат "вн.тер.г.";
	КонецЕсли;

	Если СтрСравнить(ТипОбъекта, "мун.окр.") = 0 Или СтрСравнить(ТипОбъекта, "мун. окр.") = 0 Тогда
		Возврат "м.о.";
	КонецЕсли;
	// АПК: 1297-вкл

	Возврат ТипОбъекта;

КонецФункции


// Поиск первого файла по маске без учета регистра (особенностей операционной системы).
//
// Параметры:
//     Каталог         - Строка - каталог, в котором ищется файл.
//     МаскаИмениФайла - Строка - имя искомого файла.
//
// Возвращаемое значение:
//     Структура - описание найденного файла. Содержит поля:
//         * Существует       - Булево - флаг того, что указанный файл существует.
//         * Имя              - Строка - характеристика найденного файла, см. описания типа Файл.
//         * ИмяБезРасширения - Строка - характеристика найденного файла, см. описания типа Файл.
//         * ПолноеИмя        - Строка - характеристика найденного файла, см. описания типа Файл.
//         * Путь             - Строка - характеристика найденного файла, см. описания типа Файл.
//         * Расширение       - Строка - характеристика найденного файла, см. описания типа Файл.
//
Функция НайтиФайл(Каталог, МаскаИмениФайла)

	НеУчитыватьРегистр = ОбщегоНазначения.ЭтоWindowsСервер();

	Если НеУчитыватьРегистр Тогда
		Маска = ВРег(МаскаИмениФайла);
	Иначе
		Маска = "";
		Для Позиция = 1 По СтрДлина(МаскаИмениФайла) Цикл
			Символ = Сред(МаскаИмениФайла, Позиция, 1);
			ВерхнийРегистр = ВРег(Символ);
			НижнийРегистр  = НРег(Символ);
			Если ВерхнийРегистр = НижнийРегистр Тогда
				Маска = Маска + Символ;
			Иначе
				Маска = Маска + "[" + ВерхнийРегистр + НижнийРегистр + "]";
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Результат = Новый Структура("Существует, Имя, ИмяБезРасширения, ПолноеИмя, Путь, Расширение", Ложь);
	Варианты = НайтиФайлы(Каталог, Маска);
	Если Варианты.Количество() > 0 Тогда
		Результат.Существует = Истина;
		ЗаполнитьЗначенияСвойств(Результат, Варианты[0]);
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Завершает работу с набором данных.
//
Процедура ЗакрытьФайлЗагрузкиСубъектаРФ(ОписаниеФайла)

	ОписаниеФайла.ФайлЧтения.Закрыть();
	ОписаниеФайла.ФайлЧтения = Неопределено;

	Если ОписаниеФайла.УдалитьПутьПриЗакрытии Тогда
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Примечание,,,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Удаление файла региона %1'"),
				ОписаниеФайла.Путь));
		ФайловаяСистема.УдалитьВременныйФайл(ОписаниеФайла.Путь);
	КонецЕсли;

КонецПроцедуры

// Противоположность ОбщегоНазначенияКлиентСервер.СтруктураURI
//
Функция URIПоСтруктуре(СтруктураURI)
	Результат = "";
	
	// Протокол
	Если Не ПустаяСтрока(СтруктураURI.Схема) Тогда
		Результат = Результат + СтруктураURI.Схема + "://";
	КонецЕсли;
	
	// Авторизация
	Если Не ПустаяСтрока(СтруктураURI.Логин) Тогда
		Результат = Результат + СтруктураURI.Логин + ":" + СтруктураURI.Пароль + "@";
	КонецЕсли;
		
	// Все остальное
	Результат = Результат + СтруктураURI.Хост;
	Если Не ПустаяСтрока(СтруктураURI.Порт) Тогда
		Результат = Результат + ":" + ?(ТипЗнч(СтруктураURI.Порт) = Тип("Число"), Формат(СтруктураURI.Порт, ""),
			СтруктураURI.Порт);
	КонецЕсли;

	Результат = Результат + "/" + СтруктураURI.ПутьНаСервере;
	Возврат Результат;

КонецФункции

// Подстановка порта в адрес загрузки для профилей безопасности.
//
Функция АдресИнтернетаВключаяПорт(Адрес)

	Результат = Новый Структура;

	СоставАдреса = ОбщегоНазначенияКлиентСервер.СтруктураURI(Адрес);
	Если ПустаяСтрока(СоставАдреса.Порт) Тогда
		Протокол = ВРег(СоставАдреса.Схема);
		Если Протокол = "HTTP" Тогда
			СоставАдреса.Порт = 80;
		ИначеЕсли Протокол = "HTTPS" Тогда
			СоставАдреса.Порт = 443;
		КонецЕсли;

		Результат.Вставить("Адрес", URIПоСтруктуре(СоставАдреса));
	Иначе
		Результат.Вставить("Адрес", Адрес);
	КонецЕсли;

	ИмяФайла = СоставАдреса.ПутьНаСервере;
	ПозицияПараметра = СтрНайти(ИмяФайла, "?");
	Если ПозицияПараметра > 0 Тогда
		ИмяФайла = Лев(ИмяФайла, ПозицияПараметра - 1);
	КонецЕсли;
	ИмяФайла = СтрЗаменить(ИмяФайла, Символы.ПС, "");
	ИмяФайла = СтрЗаменить(ИмяФайла, "/", Символы.ПС);
	ИмяФайла = СтрЗаменить(ИмяФайла, "\", Символы.ПС);

	Результат.Вставить("ИмяФайла", СокрЛП(СтрПолучитьСтроку(ИмяФайла, СтрЧислоСтрок(ИмяФайла))));
	Возврат Результат;
КонецФункции

// Заполняет коды по структуре адреса.
//
Функция ЗаполнитьКодыАдреса(Результат, ИдентификаторАдресногоОбъекта, СведенияОДоме)

	Коды = КодыПоИдентификаторуАдресногоОбъекта(ИдентификаторАдресногоОбъекта, СведенияОДоме);
	Если Коды <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(Результат, Коды);

		Для Каждого КлючЗначение Из Результат Цикл
			Если СтрСравнить(КлючЗначение.Ключ, "Идентификатор") <> 0 Тогда
				Результат[КлючЗначение.Ключ] = Формат(КлючЗначение.Значение, "ЧГ=0");
				Если (СтрСравнить(КлючЗначение.Ключ, "ОКТМО") = 0
				   Или СтрСравнить(КлючЗначение.Ключ, "ОКТМОБюджетополучателя") = 0)
				   И СтрДлина(Результат[КлючЗначение.Ключ]) <> 8
				   И СтрДлина(Результат[КлючЗначение.Ключ]) <> 11 Тогда
					Результат[КлючЗначение.Ключ] = "0" + Результат[КлючЗначение.Ключ];
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;

		Результат.Вставить("ИдентификаторДома", 
			?(ЗначениеЗаполнено(Коды.ИдентификаторДома), Коды.ИдентификаторДома, ""));
		Возврат Истина;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

Функция ВыполнитьЗапросЧерезВебСервис(СтрокаЗапроса, ВремяОжидания = 60)
	
	Результат = НовыйОтветИзВебСервиса();

	Если АдресныйКлассификаторПовтИсп.ИспользоватьТолькоЗагруженныеДанные() Тогда
		Возврат Результат;
	КонецЕсли;

	Сервис = АдресныйКлассификаторПовтИсп.СервисКлассификатора1С(ВремяОжидания);


	ТекстURL = ПрефиксВерсииЗапроса() + СтрокаЗапроса;
	HTTPЗапрос = Новый HTTPЗапрос(ТекстURL);

	Попытка
		Ответ = Сервис.Получить(HTTPЗапрос);
	Исключение

		ОбработатьОшибкуОбращенияКВебСервису(Результат, Ответ, ИнформацияОбОшибке(), ТекстURL);
		Возврат Результат;

	КонецПопытки;

	Результат.Отказ = Ложь;
	Результат.КодСостояния = Ответ.КодСостояния;

	Если Результат.КодСостояния = 200 Тогда

		ПолученныеДанные = Ответ.ПолучитьТелоКакСтроку("UTF-8");
		Если ПустаяСтрока(ПолученныеДанные) Тогда
			Результат.Отказ = Истина;
			Возврат Результат;
		КонецЕсли;
		
		Результат.Данные = СтрокуJSONВСтруктуру(ПолученныеДанные);

	Иначе

		ОбработатьОшибкуОбращенияКВебСервису(Результат, Ответ, ИнформацияОбОшибке(), ТекстURL);

	КонецЕсли;

	Возврат Результат;

КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Отказ - Булево
//   * ПодробноеПредставлениеОшибки - Строка
//   * КодСостояния - Число
//   * Данные - Структура
//
Функция НовыйОтветИзВебСервиса()
	
	Результат = Новый Структура;
	Результат.Вставить("Отказ",                        Истина);
	Результат.Вставить("ПодробноеПредставлениеОшибки", "");
	Результат.Вставить("КодСостояния",                 0);
	Результат.Вставить("Данные",                       Новый Структура);
	
	Возврат Результат;
	
КонецФункции

Процедура ОбработатьОшибкуОбращенияКВебСервису(Результат, Знач Ответ, ИнформацияОбОшибке, ТекстURL)

	Результат.Отказ = Истина;
	Если Ответ = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
	Если ПустаяСтрока(ПредставлениеОшибки) Тогда
		ПредставлениеОшибки = НСтр("ru = 'Веб-сервис для работы с адресами не доступен по причине:
						|- не подключена интернет-поддержка пользователей;
						|- неполадки у интернет-провайдера;
						|- подключение к серверу блокирует межсетевой экран, 
						|  антивирусная программа или другое программное обеспечение;
						|- сервис отключен или на техническом обслуживании.'");
	КонецЕсли;

	ДополнитьПредставлениеОшибкиСтекомВызовов(ПредставлениеОшибки);

	Результат.ПодробноеПредставлениеОшибки = ПредставлениеОшибки;
	ОтветОтСервера = Ответ.ПолучитьТелоКакСтроку("UTF-8");

	ЗаписатьОшибкуЗапросаКВебСервисуВЖурналРегистрации(ОтветОтСервера, Результат, ТекстURL, Ответ.КодСостояния);

КонецПроцедуры

Процедура ДополнитьПредставлениеОшибкиСтекомВызовов(ПредставлениеОшибки)

	Попытка
		ВызватьИсключение ПредставлениеОшибки;
	Исключение
		ДанныеОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ДанныеОбОшибке);
	КонецПопытки;

КонецПроцедуры

Процедура ЗаписатьОшибкуЗапросаКВебСервисуВЖурналРегистрации(ОтветОтСервераСтрокой, Результат, ТекстURL, КодСостояния)

	ШаблонТекстОтветаСервера = НСтр("ru = '%1
									|Техническая информация. При запросе: %2
									|сервер вернул HTTP Код: %3
									|с текстом: %4'");

	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстОтветаСервера,
		Результат.ПодробноеПредставлениеОшибки, ТекстURL, КодСостояния, ОтветОтСервераСтрокой);

	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);

КонецПроцедуры

// Конвертация

Функция СтруктураВСтрокуJSON(Значение)

	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();

	ЗаписатьJSON(ЗаписьJSON, Значение, , "АдаптацияПолейКонтактнойИнформации", АдресныйКлассификаторСлужебный);

	Возврат ЗаписьJSON.Закрыть();

КонецФункции

Функция АдаптацияПолейКонтактнойИнформации(Свойство, Значение, ДополнительныеПараметрыФункцииПреобразования, Отказ) Экспорт

	Если ТипЗнч(Значение) = Тип("Null") Тогда
		Возврат "";
	КонецЕсли;

	Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
		Возврат Строка(Значение);
	КонецЕсли;

КонецФункции

Функция JSONВКонтактнуюИнформациюПоПолям(Значение)

	Результат = ОписаниеНовойКонтактнойИнформации();

	КонтактнаяИнформация = СтрокуJSONВСтруктуру(Значение);
	ЗаполнитьЗначенияСвойств(Результат, КонтактнаяИнформация);

	УстановкаТипаКузбассКемеровскойОбластиКакВГАР(Результат); 
	
	Возврат Результат;

КонецФункции

Функция СтрокуJSONВСтруктуру(Значение)

	ЧтениеJSON = Новый ЧтениеJSON;
	ЧтениеJSON.УстановитьСтроку(Значение);

	Результат = ПрочитатьJSON(ЧтениеJSON, , , , "ВосстановлениеПолейКонтактнойИнформации",
		АдресныйКлассификаторСлужебный);

	ЧтениеJSON.Закрыть();

	Возврат Результат;

КонецФункции

Функция ВосстановлениеПолейКонтактнойИнформации(Свойство, Значение, ДополнительныеПараметрыФункцииПреобразования) Экспорт

	Если СтрЗаканчиваетсяНа(ВРег(Свойство), "ID") И СтрДлина(Значение) = 36 Тогда
		Возврат Новый УникальныйИдентификатор(Значение);
	КонецЕсли;

	Если СтрСравнить(Свойство, "houseType") = 0 Тогда
		Возврат ТРег(Значение);
	КонецЕсли;
	
	Если (СтрСравнить(Свойство, "munLevels") = 0 
		 Или СтрСравнить(Свойство, "admLevels") = 0 )
		 И ТипЗнч(Значение) <> Тип("Массив") Тогда
			Возврат Новый Массив;
	КонецЕсли;
	
	Если (СтрСравнить(Свойство, "buildings") = 0
	   Или СтрСравнить(Свойство, "apartments") = 0)
	   И ТипЗнч(Значение) = Тип("Массив") Тогда
		
		Для Каждого ЗначениеМассива Из Значение Цикл
			ЗначениеМассива.type = ТРег(ЗначениеМассива.type);
		КонецЦикла;
		
		Возврат Значение;
	КонецЕсли;

КонецФункции

// Описание национальных полей структуры контактной информации для хранения ее в формате JSON.
// Основной список полей определяется в одноименной функции общего модуля .
//
//    ТипКонтактнойИнформации  - ПеречислениеСсылка.ТипыКонтактнойИнформации -
//                                Тип контактной информации, определяющий состав полей контактной информации.
//
// Возвращаемое значение:
//   Структура - поля контактной информации c типом Адрес добавленные к основным полям:
//     * ID - Строка -  идентификационный код последнего адресного объекта в иерархи адреса.
//     * AddressType - Строка - установленный пользователем тип адреса(только для адресов РФ).
//                              Варианты: "Муниципальный", "Административно-территориальный".
//     * AreaCode - Строка - код региона РФ.
//     * AreaID - Строка - идентификатор региона.
//     * District - Строка - представление района у адресов по административно-территориальному делению.
//     * DistrictType - Строка - тип района у адресов по административно-территориальному делению.
//     * DistrictID - Строка - идентификатор региона у адресов по административно-территориальному делению.
//     * MunDistrict - Строка - представление муниципального района у адресов по муниципальному делению.
//     * MunDistrictType - Строка - тип муниципального района у адресов по муниципальному делению.
//     * MunDistrictID - Строка - идентификатор муниципального района у адресов по муниципальному делению.
//     * CityID - Строка - идентификатор муниципального города у адресов по административно-территориальному делению.
//     * Settlement - Строка - представление поселения у адресов по муниципальному делению.
//     * SettlementType - Строка - тип поселения у адресов по муниципальному делению.
//     * SettlementID - Строка - идентификатор поселения.
//     * CityDistrict - Строка - представление внутригородского района.
//     * CityDistrictType - Строка - тип внутригородского района.
//     * CityDistrictID - Строка - идентификатор внутригородского района.
//     * Territory - Строка - представление территории (элемента планировочной структуры).
//     * TerritoryType - Строка - тип территории (элемента планировочной структуры).
//     * TerritoryID - Строка - идентификатор территории (элемента планировочной структуры).
//     * Locality - Строка - представление населенного пункта.
//     * LocalityType - Строка - тип населенного пункта.
//     * LocalityID - Строка - идентификатор населенного пункта.
//     * StreetID - Строка - идентификатор улицы.
//     * HouseType - Строка - тип дома, владения.
//     * HouseNumber - Строка - номер дома, владения.
//     * HouseID - Строка - идентификатор дома.
//     * Buildings - Массив - содержит структуры(поля структуры: type, number) с перечнем корпусов (строений) адреса.
//     * Apartments - Массив - содержит структуры(поля структуры: type, number) с перечнем помещений адреса.
//     * CodeKLADR - Строка - код КЛАДР.
//     * OKTMO - Строка - код ОКТМО.
//     * OKATO - Строка - код ОКАТО.
//     * IFNSFLCode - Строка - код ИФНСФЛ.
//     * IFNSULCode - Строка - код ИФНСЮЛ.
//     * IFNSFLAreaCode - Строка - код участка ИФНСФЛ.
//     * IFNSULAreaCode - Строка - код участка ИФНСЮЛ.
//     * admLevels - Массив - порядок административных полей в представлении адреса
//     * munLevels - Массив - порядок муниципальных полей в представлении адреса
//
Функция ОписаниеНовойКонтактнойИнформации()

	Результат = Новый Структура;

	Результат.Вставить("version", 4);
	Результат.Вставить("value", "");
	Результат.Вставить("comment", "");
	Результат.Вставить("type", "Адрес");
	Результат.Вставить("country", "");
	Результат.Вставить("addressType", АдресВСвободнойФорме());
	Результат.Вставить("countryCode",      "");
	Результат.Вставить("ZIPcode",          "");
	Результат.Вставить("area",             "");
	Результат.Вставить("areaType",         "");
	Результат.Вставить("areaValue",        "");
	Результат.Вставить("city",             "");
	Результат.Вставить("cityType",         "");
	Результат.Вставить("street",           "");
	Результат.Вставить("streetType",       "");
	Результат.Вставить("id",               "");
	Результат.Вставить("areaCode",         "");
	Результат.Вставить("areaId",           "");
	Результат.Вставить("district",         "");
	Результат.Вставить("districtType",     "");
	Результат.Вставить("districtId",       "");
	Результат.Вставить("munDistrict",      "");
	Результат.Вставить("munDistrictType",  "");
	Результат.Вставить("munDistrictId",    "");
	Результат.Вставить("cityId",           "");
	Результат.Вставить("settlement",       "");
	Результат.Вставить("settlementType",   "");
	Результат.Вставить("settlementId",     "");
	Результат.Вставить("cityDistrict",     "");
	Результат.Вставить("cityDistrictType", "");
	Результат.Вставить("cityDistrictId",   "");
	Результат.Вставить("territory",        "");
	Результат.Вставить("territoryType",    "");
	Результат.Вставить("territoryId",      "");
	Результат.Вставить("locality",         "");
	Результат.Вставить("localityType",     "");
	Результат.Вставить("localityId",       "");
	Результат.Вставить("streetId",         "");
	Результат.Вставить("houseType",        "");
	Результат.Вставить("houseNumber",      "");
	Результат.Вставить("houseId",          "");
	Результат.Вставить("stead",            "");
	Результат.Вставить("steadId",          "");
	Результат.Вставить("buildings", Новый Массив);
	Результат.Вставить("apartments", Новый Массив);
	Результат.Вставить("codeKLADR",      "");
	Результат.Вставить("oktmo",          "");
	Результат.Вставить("oktmoBudget",    "");
	Результат.Вставить("okato",          "");
	Результат.Вставить("asInDocument",   "");
	Результат.Вставить("ifnsFLCode",     "");
	Результат.Вставить("ifnsULCode",     "");
	Результат.Вставить("ifnsFLAreaCode", "");
	Результат.Вставить("ifnsULAreaCode", "");
	Результат.Вставить("admLevels", Новый Массив);
	Результат.Вставить("munLevels", Новый Массив);

	Возврат Результат;

КонецФункции

Процедура СписокДомовИзЗагруженныхСведений(Знач ВариантыДомов, Знач ИдентификаторАдресногоОбъекта, Знач СтрокаПоиска,
	Знач ТочноеСовпадение)

	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ДомаЗданияСтроения.Строения КАК Строения,
	|	ЕСТЬNULL(ДополнительныеСведения.ОКТМО, """") КАК ОКТМО,
	|	ЕСТЬNULL(ДополнительныеСведения.ПочтовыйИндекс, """") КАК ПочтовыйИндекс,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСФЛ, """") КАК КодИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСЮЛ, """") КАК КодИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСФЛ, """") КАК КодУчасткаИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСЮЛ, """") КАК КодУчасткаИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.OKATO, """") КАК ОКАТО,
	|	ЕСТЬNULL(АдресныеОбъекты.КодКЛАДР, """") КАК КодКЛАДР
	|ИЗ
	|	РегистрСведений.ДомаЗданияСтроения КАК ДомаЗданияСтроения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (ДополнительныеСведения.Идентификатор = ДомаЗданияСтроения.ДополнительныеАдресныеСведения)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Идентификатор = ДомаЗданияСтроения.АдресныйОбъект)
	|ГДЕ
	|	ДомаЗданияСтроения.АдресныйОбъект = &АдресныйОбъект";

	Запрос.УстановитьПараметр("АдресныйОбъект", ИдентификаторАдресногоОбъекта);
	Запись = Запрос.Выполнить().Выбрать();

	Пока Запись.Следующий() Цикл
		Если ЗначениеЗаполнено(Запись.Строения) Тогда
			Описание = Запись.Строения.Получить();
			Если ЗначениеЗаполнено(Описание) Тогда
				ИзвлечьСписокДомов(Описание, СтрокаПоиска, ВариантыДомов, Запись, ТочноеСовпадение);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

// Возвращаемое значение:
//  ТаблицаЗначений:
//   * ДомЧислом - Число
//   * Дом - Строка
//   * ДополнительныйДом1 - Строка
//   * ДополнительныйДом2 - Строка
//   * Значение - Структура
//   * Представление - Строка
//   * Идентификатор - Строка
//
Функция КонструкторСпискаДомов() Экспорт

	ВариантыДомов = Новый ТаблицаЗначений;
	ВариантыДомов.Колонки.Добавить("ДомЧислом", ОбщегоНазначения.ОписаниеТипаЧисло(15));
	ВариантыДомов.Колонки.Добавить("Дом", ОбщегоНазначения.ОписаниеТипаСтрока(30));
	ВариантыДомов.Колонки.Добавить("ДополнительныйДом1", ОбщегоНазначения.ОписаниеТипаСтрока(30));
	ВариантыДомов.Колонки.Добавить("ДополнительныйДом2", ОбщегоНазначения.ОписаниеТипаСтрока(30));
	ВариантыДомов.Колонки.Добавить("Значение");
	ВариантыДомов.Колонки.Добавить("Представление", ОбщегоНазначения.ОписаниеТипаСтрока(200));
	ВариантыДомов.Колонки.Добавить("Идентификатор", ОбщегоНазначения.ОписаниеТипаСтрока(50));

	Возврат ВариантыДомов;

КонецФункции

// Возвращаемое значение:
//  Массив из Строка
//
Функция СопоставлениеУровнейАдреса()

	Уровни = Новый Массив;
	Уровни.Добавить("Area");
	Уровни.Добавить("MunDistrict");
	Уровни.Добавить("District");
	Уровни.Добавить("Settlement");
	Уровни.Добавить("City");
	Уровни.Добавить("CityDistrict");
	Уровни.Добавить("Locality");
	Уровни.Добавить("Territory");
	Уровни.Добавить("Street");

	Возврат Уровни;

КонецФункции

Процедура УстановитьЗначениеУровняАдреса(Адрес, СтруктураДанных, ИмяУровня)

	Адрес[ИмяУровня]          = СокрЛП(СтруктураДанных[ИмяУровня]);
	Адрес[ИмяУровня + "Type"] = СокрЛП(СтруктураДанных[ИмяУровня + "Type"]);
	Адрес[ИмяУровня + "Id"]   = СтруктураДанных[ИмяУровня + "Id"];

КонецПроцедуры

// Возвращает структуру, описывающую населенный пункт в иерархии младший-старший
//  для текущего адресного классификатора. Имена ключей структуры зависят от 
//  классификатора.
//
//  Параметры:
//      Идентификатор - УникальныйИдентификатор - идентификатор объекта. Если указан, то структура 
//                                                заполняется данными для этого объекта.
//      ВариантКлассификатора                   - Строка - требуемый вид классификатора. 
// 
// Возвращаемое значение:
//      Структура - описание населенного пункта.
//
Функция СформироватьАдресПоДаннымИзКлассификатора(АдресныеСведенияДанные)

	Адрес = ОписаниеНовойКонтактнойИнформации();

	ЗаполнитьЗначенияСвойств(Адрес, АдресныеСведенияДанные);

	Если ПустаяСтрока(Адрес.Country) Тогда
		Адрес.Вставить("Country", Строка(ОсновнаяСтрана()));
	КонецЕсли;

	Для Каждого ИмяУровня Из СопоставлениеУровнейАдреса() Цикл
		УстановитьЗначениеУровняАдреса(Адрес, АдресныеСведенияДанные, ИмяУровня);
	КонецЦикла;

	Возврат Адрес;
КонецФункции

/////////////////////////////////////
// Обратная совместимость

// Возвращает признак того, является ли строка данных контактной информации XML данными.
//
// Параметры:
//     Текст - Строка - проверяемая строка.
//
// Возвращаемое значение:
//     Булево - результат проверки.
//
Функция ЭтоКонтактнаяИнформацияВXML(Знач Текст)

	Возврат ТипЗнч(Текст) = Тип("Строка") И СтрНачинаетсяС(СокрЛ(Текст), "<");

КонецФункции

Функция АдресВСвободнойФорме()
	Возврат "ВСвободнойФорме";
КонецФункции

// Возвращает значения уровней 90(дополнительный элемент) и 91(подчиненный) из адреса.
//
Функция ЗначениеДополнительныхЭлементов(Знач XDTOАдрес)

	Результат = Новый Структура("ДополнительныйЭлемент, ПодчиненныйЭлемент");

	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	ДополнительныйЭлементАдреса = НайтиДополнительныйЭлементАдреса(АдресРФ).Значение;

	Результат.ДополнительныйЭлемент = ДополнительныйЭлементАдреса;
	Результат.ПодчиненныйЭлемент = ДополнительныйЭлементАдреса(АдресРФ, XPathДополнительногоОбъектаАдресации(91));

	Возврат Результат;

КонецФункции

// Читает и устанавливает здания и помещения адреса. 
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      НовоеЗначение - Структура  - устанавливаемое значение. Ожидаются поля:
//                          * Здания - ТаблицаЗначений:
//                                        ** Тип      - Строка - тип внутреннего классификатора дополнительных адресных
//                                                               объектов. Например "Корпус".
//                                        ** Значение - Строка  - значение номера дома, квартиры и т.п.
//                          * Помещения - ТаблицаЗначений - с колонками, аналогично полю Здание.
//
//  Возвращаемое значение:
//      Структура - текущие данные. Содержит поля:
//          * Здания - ТаблицаЗначений:
//                        ** Тип        - Строка - тип внутреннего классификатора дополнительных адресных объектов.
//                                                 Например "Корпус".
//                        ** Сокращение - Строка - сокращение названия для использования в представлении.
//                        ** Значение   - Строка - значение номера дома, квартиры и т.п.
//                        ** ПутьXPath  - Строка - путь к значению объекта.
//          * Помещения - ТаблицаЗначений - с колонками, аналогично полю Здание.
//
Функция ЗданияИПомещенияАдреса(XDTOАдрес, НовоеЗначение = Неопределено)

	Результат = Новый Структура("Здания, Помещения", 
		ТаблицаЗначений("Тип, Значение, Сокращение, ПутьXPath, Вид", "Тип, Вид"), 
		ТаблицаЗначений("Тип, Значение, Сокращение, ПутьXPath, Вид", "Тип, Вид"));
		
	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	Если НовоеЗначение <> Неопределено Тогда
		// Запись
		Если НовоеЗначение.Свойство("Здания") Тогда
			Для Каждого Строка Из НовоеЗначение.Здания Цикл
				ВставитьЗданиеПомещение(XDTOАдрес, Строка.Тип, Строка.Значение);
			КонецЦикла;
		КонецЕсли;
		Если НовоеЗначение.Свойство("Помещения") Тогда
			Для Каждого Строка Из НовоеЗначение.Помещения Цикл
				ВставитьЗданиеПомещение(XDTOАдрес, Строка.Тип, Строка.Значение);
			КонецЦикла;
		КонецЕсли;
		Возврат НовоеЗначение
	КонецЕсли;
	
	// Чтение
	Для Каждого ДопЭлемент Из АдресРФ.ДопАдрЭл Цикл
		Если ДопЭлемент.Номер <> Неопределено Тогда
			КодОбъекта = ДопЭлемент.Номер.Тип;
			ТипОбъекта = ТипОбъектаПоКодуСериализации(КодОбъекта);
			Если ТипОбъекта <> Неопределено Тогда
				Вид = ТипОбъекта.Тип;
				Если Вид = 1 Или Вид = 2 Тогда
					НоваяСтрока = Результат.Здания.Добавить();
				ИначеЕсли Вид = 3 Тогда
					НоваяСтрока = Результат.Помещения.Добавить();
				Иначе
					НоваяСтрока = Неопределено;
				КонецЕсли;
				Если НоваяСтрока <> Неопределено Тогда
					НоваяСтрока.Тип        = ТипОбъекта.Наименование;
					НоваяСтрока.Значение   = ДопЭлемент.Номер.Значение;
					НоваяСтрока.Сокращение = ТипОбъекта.Сокращение;
					НоваяСтрока.ПутьXPath  = XPathНомераДополнительногоОбъектаАдресации(НоваяСтрока.Тип);
					НоваяСтрока.Вид        = Вид;
				КонецЕсли;
			Иначе
				НоваяСтрока = Результат.Помещения.Добавить();
				НоваяСтрока.Тип        = ДопЭлемент.Номер.Тип;
				НоваяСтрока.Значение   = ДопЭлемент.Номер.Значение;
				НоваяСтрока.Сокращение = ДопЭлемент.Номер.Тип;
				НоваяСтрока.ПутьXPath  = XPathНомераДополнительногоОбъектаАдресации("2000");
				НоваяСтрока.Вид        = 3;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

	Результат.Здания.Сортировать("Вид");
	Результат.Помещения.Сортировать("Вид");

	Возврат Результат;
КонецФункции

Процедура ВставитьЗданиеПомещение(XDTOАдрес, Тип, Значение)
	Если ПустаяСтрока(Значение) Тогда
		Возврат;
	КонецЕсли;

	Запись = XDTOАдрес.Получить(XPathНомераДополнительногоОбъектаАдресации(Тип));
	Если Запись = Неопределено Тогда
		Запись = XDTOАдрес.ДопАдрЭл.Добавить( ФабрикаXDTO.Создать(XDTOАдрес.ДопАдрЭл.ВладеющееСвойство.Тип));
		Запись.Номер = ФабрикаXDTO.Создать(Запись.Свойства().Получить("Номер").Тип);
		Запись.Номер.Значение = Значение;

		КодТипа = КодСериализацииОбъектаАдресации(Тип);
		Если КодТипа = Неопределено Тогда
			КодТипа = Тип;
		КонецЕсли;
		Запись.Номер.Тип = КодТипа;
	Иначе
		Запись.Значение = Значение;
	КонецЕсли;

КонецПроцедуры

// Конструктор таблицы значений.
//
Функция ТаблицаЗначений(СписокКолонок, СписокИндексов = "")
	ТаблицаРезультата = Новый ТаблицаЗначений;

	Для Каждого КлючЗначение Из (Новый Структура(СписокКолонок)) Цикл
		ТаблицаРезультата.Колонки.Добавить(КлючЗначение.Ключ);
	КонецЦикла;

	СтрокиИндексов = СтрЗаменить(СписокИндексов, "|", Символы.ПС);
	Для НомерИндекса = 1 По СтрЧислоСтрок(СтрокиИндексов) Цикл
		КолонкиИндекса = СокрЛП(СтрПолучитьСтроку(СтрокиИндексов, НомерИндекса));
		Для Каждого КлючЗначение Из (Новый Структура(КолонкиИндекса)) Цикл
			ТаблицаРезультата.Индексы.Добавить(КлючЗначение.Ключ);
		КонецЦикла;
	КонецЦикла;

	Возврат ТаблицаРезультата;
КонецФункции

Функция КодСериализацииДополнительногоОбъектаАдресации(Уровень, ТипаАдресногоЭлемента = "")

	Если Уровень = 90 Тогда
		Если ВРег(ТипаАдресногоЭлемента) = "ГСК" Тогда
			Возврат "10600000";
		ИначеЕсли ВРег(ТипаАдресногоЭлемента) = "СНТ" Тогда
			Возврат "10300000";
		ИначеЕсли ВРег(ТипаАдресногоЭлемента) = "ТЕР" Тогда
			Возврат "10700000";
		Иначе
			Возврат "10200000";
		КонецЕсли;
	ИначеЕсли Уровень = 91 Тогда
		Возврат "10400000";
	КонецЕсли;
	
	// Все остальное - считаем ориентиром.
	Возврат "Местоположение";
КонецФункции

// Возвращает XPath для дополнительного объекта адресации по умолчанию.
//
//  Параметры:
//      Уровень - Число - уровень объекта. 90  - дополнительный(Варианты: ГСК, СНТ, ТЕР), 91 - подчиненный, -1 -
//                        Ориентир.
//
// Возвращаемое значение:
//      Строка - XPath
//
Функция XPathДополнительногоОбъектаАдресации(Уровень, ТипаАдресногоЭлемента = "")
	КодСериализации = КодСериализацииДополнительногоОбъектаАдресации(Уровень, ТипаАдресногоЭлемента);
	Возврат "ДопАдрЭл[ТипАдрЭл='" + КодСериализации + "']";
КонецФункции

Функция ПочтовыйИндексАдреса(XDTOАдрес, НовоеЗначение = Неопределено)

	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	Если НовоеЗначение = Неопределено Тогда
		// Чтение
		Результат = АдресРФ.Получить(XPathПочтовогоИндекса());
		Если Результат <> Неопределено Тогда
			Результат = Результат.Значение;
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	
	// Запись
	КодИндекса = КодСериализацииПочтовогоИндекса();

	ЗаписьИндекса = АдресРФ.Получить(XPathПочтовогоИндекса());
	Если ЗаписьИндекса = Неопределено Тогда
		ДопАдрЭл = АдресРФ.ДопАдрЭл; // СписокXDTO
		ЗаписьИндекса = ДопАдрЭл.Добавить(ФабрикаXDTO.Создать(XDTOАдрес.ДопАдрЭл.ВладеющееСвойство.Тип));
		ЗаписьИндекса.ТипАдрЭл = КодИндекса;
	КонецЕсли;

	ЗаписьИндекса.Значение = СокрЛП(НовоеЗначение);
	Возврат НовоеЗначение;
КонецФункции

Функция КодСериализацииОбъектаАдресации(СтрокаЗначения)

	Ключ = ВРег(СокрЛП(СтрокаЗначения));
	Для Каждого Элемент Из ТипыОбъектовАдресацииАдресаРФ() Цикл
		Если Элемент.Ключ = Ключ Тогда
			Возврат Элемент.Код;
		КонецЕсли;
	КонецЦикла;

	Возврат Неопределено;
КонецФункции

// Возвращает массив структур с информацией о частях адреса согласно приказу ФНС ММВ-7-1/525 от 31.08.2011.
//
// Возвращаемое значение:
//   Массив из см. СтрокаОбъектаАдресации
//
Функция ТипыОбъектовАдресацииАдресаРФ()
	
	Результат = Новый Массив;
	
	// Код, Наименование, Тип, Порядок, КодАдресногоКлассификатора
	// Тип: 1 - владение, 2 - здание, 3 - помещение.
	
	Результат.Добавить(СтрокаОбъектаАдресации("1010", "Дом", 1, 1, 2)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1020", "Владение", 1, 2, 1)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1030", "Домовладение", 1, 3, 3)); // не локализуется
	
	Результат.Добавить(СтрокаОбъектаАдресации("1050", "Корпус", 2, 1)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1060", "Строение", 2, 2, 1)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1080", "Литера", 2, 3, 3)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1090", "Литер", 2, 6, 3)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1070", "Сооружение", 2, 4, 2)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("1040", "Участок", 2, 5)); // не локализуется
	
	Результат.Добавить(СтрокаОбъектаАдресации("2010", "Квартира", 3, 1)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2030", "Офис", 3, 2)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2040", "Бокс", 3, 3)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2020", "Помещение", 3, 4)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2050", "Комната", 3, 5)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2060", "Этаж", 3, 6)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2070", "А/я", 3, 7)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2080", "В/ч", 3, 8)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2090", "П/о", 3, 9)); // не локализуется
	//  Наши сокращения для поддержки обратной совместимости при парсинге.
	Результат.Добавить(СтрокаОбъектаАдресации("2010", "кв.", 3, 6)); // не локализуется
	Результат.Добавить(СтрокаОбъектаАдресации("2030", "оф.", 3, 7)); // не локализуется
	// Ввод помещения вручную.
	Результат.Добавить(СтрокаОбъектаАдресации("2000", "", 3, 0));
	
	// Уточняющие объекты
	Результат.Добавить(СтрокаОбъектаАдресации("10100000", НСтр("ru = 'Почтовый индекс'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10200000", НСтр("ru = 'Адресная точка'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10300000", НСтр("ru = 'Садовое товарищество'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10400000", 
		НСтр("ru = 'Элемент улично-дорожной сети, планировочной структуры дополнительного адресного элемента'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10500000", НСтр("ru = 'Промышленная зона'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10600000", НСтр("ru = 'Гаражно-строительный кооператив'")));
	Результат.Добавить(СтрокаОбъектаАдресации("10700000", НСтр("ru = 'Территория'")));
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Код - Строка
//  Наименование - Строка
//  Тип - Число
//  Порядок - Число
//  КодАдресногоКлассификатора - Число
// Возвращаемое значение:
//  Структура:
//   * Ключ - Строка
//   * Сокращение - Строка
//   * КодАдресногоКлассификатора - Число
//   * Порядок - Число
//   * Тип - Число
//   * Наименование - Строка
//   * Код - Строка
// 
Функция СтрокаОбъектаАдресации(Код, Наименование, Тип = 0, Порядок = 0, КодАдресногоКлассификатора = 0)

	СтруктураОбъектаАдресации = Новый Структура;
	СтруктураОбъектаАдресации.Вставить("Код", Код);
	СтруктураОбъектаАдресации.Вставить("Наименование", Наименование);
	СтруктураОбъектаАдресации.Вставить("Тип", Тип);
	СтруктураОбъектаАдресации.Вставить("Порядок", Порядок);
	СтруктураОбъектаАдресации.Вставить("КодАдресногоКлассификатора", КодАдресногоКлассификатора);
	СтруктураОбъектаАдресации.Вставить("Сокращение", НРег(Наименование));
	СтруктураОбъектаАдресации.Вставить("Ключ", ВРег(Наименование));
	Возврат СтруктураОбъектаАдресации;

КонецФункции

// Возвращает код дополнительной части адреса для почтового индекса.
//
// Возвращаемое значение:
//      Строка - код
//
Функция КодСериализацииПочтовогоИндекса()

	Возврат КодСериализацииОбъектаАдресации(НСтр("ru = 'Почтовый индекс'"));

КонецФункции

// Читает и устанавливает район адреса.
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      НовоеЗначение - Строка - устанавливаемое значение.
//
//  Возвращаемое значение:
//      Строка - новое значение.
//
Функция РайонАдреса(XDTOАдрес, НовоеЗначение = Неопределено)

	Если НовоеЗначение = Неопределено Тогда
		// Чтение

		XDTOТип = XDTOАдрес.Тип();
		Если XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен(), "АдресРФ") 
		   Или XDTOТип = ФабрикаXDTO.Тип("http://www.v8.1c.ru/ssl/contactinfo_ru", "АдресРФ") Тогда
			АдресРФ = XDTOАдрес;
		Иначе
			АдресРФ = XDTOАдрес.Состав;
		КонецЕсли;

		Если ТипЗнч(АдресРФ) = Тип("ОбъектXDTO") Тогда
			Возврат ПолучитьXDTOРеквизитОбъекта(АдресРФ, XPathРайона());
		КонецЕсли;

		Возврат Неопределено;
	КонецЕсли;
	
	// Запись
	Запись = СвРайМО(XDTOАдрес);
	Запись.Район = НовоеЗначение;
	Возврат НовоеЗначение;

КонецФункции

Функция СвРайМО(АдресРФ)
	Если АдресРФ.СвРайМО <> Неопределено Тогда
		Возврат АдресРФ.СвРайМО;
	КонецЕсли;

	АдресРФ.СвРайМО = ФабрикаXDTO.Создать( АдресРФ.Свойства().Получить("СвРайМО").Тип);
	Возврат АдресРФ.СвРайМО;
КонецФункции

// Возвращает XPath для района.
//
// Возвращаемое значение:
//      Строка - XPath
//
Функция XPathРайона()

	Возврат "СвРайМО/Район";

КонецФункции

// Возвращает извлеченный XDTO российского адреса или Неопределено для адреса иностранного.
//
//  Параметры:
//      ОбъектИнформации - ОбъектXDTO - контактная информация или XDTO адреса.
//
//  Возвращаемое значение:
//      ОбъектXDTO - российский адрес.
//      Неопределено - нет российского адреса.
//
Функция НациональныйАдрес(ОбъектИнформации)
	Результат = Неопределено;
	ТипXDTO   = Тип("ОбъектXDTO");

	Если ТипЗнч(ОбъектИнформации) = ТипXDTO Тогда
		ПространствоИмен = ПространствоИмен();

		Если ОбъектИнформации.Тип() = ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация") Тогда
			Адрес = ОбъектИнформации.Состав;
		Иначе
			Адрес = ОбъектИнформации;
		КонецЕсли;

		Если ТипЗнч(Адрес) = ТипXDTO И Адрес.Тип() = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
			Адрес = Адрес.Состав;
		КонецЕсли;

		Если ТипЗнч(Адрес) = ТипXDTO Тогда
			Результат = Адрес;
		КонецЕсли;
	КонецЕсли;

	Возврат Результат;
КонецФункции

Функция ЗначениеСтроенияИлиПомещения(ТипОбъекта, Значение)
	Возврат Новый Структура("type, number", ТипОбъекта, Значение);
КонецФункции

// Возвращает дополнительный адреса.
//
Функция НайтиДополнительныйЭлементАдреса(АдресРФ)

	ВариантыДополнительногоЭлементаАдреса = ВариантыДополнительногоЭлементаАдреса();

	ПутьXPath = "";
	ДополнительныйЭлементАдреса = Неопределено;
	Для Каждого ВариантДополнительныйЭлементАдреса Из ВариантыДополнительногоЭлементаАдреса Цикл
		ПутьXPath = XPathДополнительногоОбъектаАдресации(90, ВариантДополнительныйЭлементАдреса);
		ДополнительныйЭлементАдреса = ДополнительныйЭлементАдреса(АдресРФ, ПутьXPath);
		Если ДополнительныйЭлементАдреса <> Неопределено Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;

	Возврат Новый Структура("Значение, XPath", ДополнительныйЭлементАдреса, ПутьXPath);

КонецФункции

Функция ВариантыДополнительногоЭлементаАдреса()

	ВариантыДополнительногоЭлементаАдреса = Новый Массив;
	ВариантыДополнительногоЭлементаАдреса.Добавить("СНТ");
	ВариантыДополнительногоЭлементаАдреса.Добавить("ГСК");
	ВариантыДополнительногоЭлементаАдреса.Добавить("ТЕР");
	ВариантыДополнительногоЭлементаАдреса.Добавить("");
	Возврат ВариантыДополнительногоЭлементаАдреса;

КонецФункции

// Читает дополнительные элемент адреса по его пути.
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      XPathЭлемента -  Строка - путь к элементу.
//
//  Возвращаемое значение:
//      Строка - значение элемента.
//
Функция ДополнительныйЭлементАдреса(XDTOАдрес, XPathЭлемента)

	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	Результат = АдресРФ.Получить(XPathЭлемента);
	Если Результат <> Неопределено Тогда
		Возврат Результат.Значение;
	КонецЕсли;

	Возврат Результат;
КонецФункции

Процедура СформироватьКодыКЛАДР(КодКЛАДР, Адрес, КодыКЛАДР)

	КодКЛАДР = Формат(КодКЛАДР, "ЧРГ=''; ЧГ=0");

	Если СтрДлина(КодКЛАДР) = 17 Тогда
		КодыКЛАДР.Улица = КодКЛАДР;
		КодКЛАДР = Лев(КодКЛАДР, 13);
	Иначе
		КодКЛАДР = Лев(КодКЛАДР, 13);
	КонецЕсли;

	Если СтрДлина(КодКЛАДР) = 12 Тогда
		КодКЛАДР = "0" + КодКЛАДР;
	КонецЕсли;

	Если СтрДлина(КодКЛАДР) = 13 Тогда

		Если ЗначениеЗаполнено(Адрес.Area) Тогда
			КодыКЛАДР.Регион = Лев(КодКЛАДР, 2) + "00000000000";
		КонецЕсли;
		Если ЗначениеЗаполнено(Адрес.District) Тогда
			КодыКЛАДР.Район = Лев(КодКЛАДР, 5) + "00000000";
		КонецЕсли;
		Если ЗначениеЗаполнено(Адрес.City) Тогда
			КодыКЛАДР.Город = Лев(КодКЛАДР, 8) + "00000";
		КонецЕсли;
		Если ЗначениеЗаполнено(Адрес.Settlement) Тогда
			КодыКЛАДР.НаселенныйПункт = Лев(КодКЛАДР, 11) + "00";
		КонецЕсли;

	КонецЕсли;

КонецПроцедуры

// Получение глубокого свойства объекта.
//
Функция ПолучитьXDTOРеквизитОбъекта(ОбъектXTDO, XPath)
	
	// Переносов строки в XPath не ожидаем.
	СтрокаСвойств = СтрЗаменить(СтрЗаменить(XPath, "/", Символы.ПС), Символы.ПС + Символы.ПС, "/");

	ЧислоСвойств = СтрЧислоСтрок(СтрокаСвойств);
	Если ЧислоСвойств = 1 Тогда
		Результат = ОбъектXTDO.Получить(СтрокаСвойств);
		Если ТипЗнч(Результат) = Тип("ОбъектXDTO") Тогда
			Возврат Результат.Значение;
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;

	Результат = ?(ЧислоСвойств = 0, Неопределено, ОбъектXTDO);
	Для Позиция = 1 По ЧислоСвойств Цикл
		Результат = Результат.Получить(СтрПолучитьСтроку(СтрокаСвойств, Позиция));
		Если Результат = Неопределено Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;

	Возврат Результат;
КонецФункции

// Возвращает строку с описанием типа по коду части адреса.
//  Противоположность функции "КодСериализацииОбъектаАдресации".
//
// Параметры:
//   Код - Строка - код
//
// Возвращаемое значение:
//   Число - тип
//
Функция ТипОбъектаПоКодуСериализации(Код)
	Для Каждого Элемент Из ТипыОбъектовАдресацииАдресаРФ() Цикл
		Если Элемент.Код = Код Тогда
			Возврат Элемент;
		КонецЕсли;
	КонецЦикла;

	Возврат Неопределено;
КонецФункции

// Возвращает XPath для номера дополнительного объекта адресации.
//
//  Параметры:
//      СтрокаЗначения - Строка - искомый тип, например "Дом", "Корпус".
//
// Возвращаемое значение:
//      Строка - XPath
//
Функция XPathНомераДополнительногоОбъектаАдресации(СтрокаЗначения)

	Код = КодСериализацииОбъектаАдресации(СтрокаЗначения);
	Если Код = Неопределено Тогда
		Код = СтрЗаменить(СтрокаЗначения, "'", "");
	КонецЕсли;

	Возврат "ДопАдрЭл/Номер[Тип='" + Код + "']";
КонецФункции

// Возвращает XPath для почтового индекса.
//
// Возвращаемое значение:
//      Строка - XPath
//
Функция XPathПочтовогоИндекса()

	Возврат "ДопАдрЭл[ТипАдрЭл='" + КодСериализацииПочтовогоИндекса() + "']";

КонецФункции

Функция АдресПустой(Знач Владелец)
	
	// Список игнорируемых при сравнении свойств текущего владельца - особенности контактной информации.
	СписокИгнорируемыхПолей = Новый Соответствие;
	СписокИгнорируемыхПолей.Вставить("value",       Истина);
	СписокИгнорируемыхПолей.Вставить("comment",     Истина);
	СписокИгнорируемыхПолей.Вставить("type",        Истина);
	СписокИгнорируемыхПолей.Вставить("addressType", Истина);
	СписокИгнорируемыхПолей.Вставить("country",     Истина);
	СписокИгнорируемыхПолей.Вставить("countryCode", Истина);
	СписокИгнорируемыхПолей.Вставить("version",     Истина);

	Для Каждого ПолеАдреса Из Владелец Цикл
		Если СписокИгнорируемыхПолей.Получить(ПолеАдреса.Ключ) <> Истина И ЗначениеЗаполнено(ПолеАдреса.Значение) Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;

	Возврат Истина;

КонецФункции

Функция КонтактнаяИнформацияВФорматеКлючЗначениеВJSON(Адрес)

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
		АдресСтруктура = КонтактнаяИнформацияВСтруктуруJSON(
			МодульУправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(Адрес));
		Возврат АдресСтруктура;
	КонецЕсли;

	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Переданный адрес не может быть преобразован в функции %1.'"),
		"АдресныйКлассификаторСлужебный.КодыАдреса");

КонецФункции

Функция ЭтоКонтактнаяИнформацияВФорматеКлючЗначение(Адрес)
	Возврат СтрНайти(ВРег(Адрес), "РЕГИОН=") > 0;
КонецФункции

Функция МаксимальныйРазмерНабораЗаписей()
	
	Возврат 3000;
	
КонецФункции

Функция ЭтоГородФедеральногоЗначения(Город)

	НазванияГородовФедеральногоЗначения = НазванияГородовФедеральногоЗначения();
	Возврат НазванияГородовФедеральногоЗначения.Получить(ВРег(Город)) = Истина;

КонецФункции

// Возвращает массив наименований регионов - городов федерального значения.
Функция НазванияГородовФедеральногоЗначения()

	СписокГородов = Новый Массив;
	СписокГородов.Добавить("МОСКВА");
	СписокГородов.Добавить("САНКТ-ПЕТЕРБУРГ");
	СписокГородов.Добавить("СЕВАСТОПОЛЬ");
	СписокГородов.Добавить("БАЙКОНУР");
	
	Результат = Новый Соответствие;
	Для Каждого Город Из СписокГородов Цикл
		Результат.Вставить(СоединитьНаименованиеИТипАдресногоОбъекта(Город, "Г", ИСТИНА), Истина);
		Результат.Вставить(СоединитьНаименованиеИТипАдресногоОбъекта("ГОРОД", Город, ИСТИНА), Истина);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Извлекает список земельных участков из регистра сведений ЗемельныеУчастки.
//
Процедура ИзвлечьСписокЗемельныхУчастков(СтрокаСоСпискомУчастков, СтрокаПоиска, ВариантыЗемельныхУчастков, Запись,
	ТочноеСовпадение)

	МассивУчастков = СтрРазделить(СтрокаСоСпискомУчастков, Символы.ПС, Ложь);

	ПодборВариантовЗемельныхУчастков = ЗначениеЗаполнено(СтрокаПоиска);

	Для Каждого Участок Из МассивУчастков Цикл
		НомерУчастка = Сред(Участок, 25);

		ОписаниеУчастка = ОписаниеДомаИЗемельногоУчастка();
		ОписаниеУчастка.НомерДома           = НомерУчастка;
		ОписаниеУчастка.ИдентификаторДома   = УникальныйИдентификаторИзСтроки64(Лев(Участок, 24));
		
		ОписаниеУчастка.Индекс           = Формат(Запись.ПочтовыйИндекс, "ЧГ=0");
		ОписаниеУчастка.ОКТМО            = Формат(Запись.ОКТМО, "ЧГ=0");
		ОписаниеУчастка.ОКАТО            = Формат(Запись.ОКАТО, "ЧГ=0");
		ОписаниеУчастка.КодИФНСФЛ        = Формат(Запись.КодИФНСФЛ, "ЧГ=0");
		ОписаниеУчастка.КодИФНСЮЛ        = Формат(Запись.КодИФНСЮЛ, "ЧГ=0");
		ОписаниеУчастка.КодУчасткаИФНСФЛ = Формат(Запись.КодУчасткаИФНСФЛ, "ЧГ=0");
		ОписаниеУчастка.КодУчасткаИФНСЮЛ = Формат(Запись.КодУчасткаИФНСЮЛ, "ЧГ=0");
		ОписаниеУчастка.КодКЛАДР         = Формат(Запись.КодКЛАДР, "ЧГ=0");

		Если ПодборВариантовЗемельныхУчастков Тогда
			Если ТочноеСовпадение И СтрСравнить(ОписаниеУчастка.НомерДома, СтрокаПоиска) = 0 Тогда
				ЗемельныйУчасток = ВариантыЗемельныхУчастков.Добавить();
				ЗемельныйУчасток.Представление = НомерУчастка;
				ЗемельныйУчасток.Значение = ОписаниеУчастка;
			ИначеЕсли СтрНайти(ВРег(ОписаниеУчастка.НомерДома), ВРег(СтрокаПоиска)) > 0 Тогда
				ЗемельныйУчасток = ВариантыЗемельныхУчастков.Добавить();
				ЗемельныйУчасток.Представление = НомерУчастка;
				ЗемельныйУчасток.Значение = ОписаниеУчастка;
			КонецЕсли;
		Иначе
			ЗемельныйУчасток = ВариантыЗемельныхУчастков.Добавить();
			ЗемельныйУчасток.Представление = НомерУчастка;
			ЗемельныйУчасток.Значение = ОписаниеУчастка;
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

Процедура СписокЗемельныхУчастковИзЗагруженныхСведений(Знач ВариантыЗемельныхУчастков,
	Знач ИдентификаторАдресногоОбъекта, Знач СтрокаПоиска, Знач ТочноеСовпадение)

	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ЗемельныеУчастки.Участки КАК Участки,
	|	ЕСТЬNULL(ДополнительныеСведения.ОКТМО, """") КАК ОКТМО,
	|	ЕСТЬNULL(ДополнительныеСведения.ПочтовыйИндекс, """") КАК ПочтовыйИндекс,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСФЛ, """") КАК КодИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодИФНСЮЛ, """") КАК КодИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСФЛ, """") КАК КодУчасткаИФНСФЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.КодУчасткаИФНСЮЛ, """") КАК КодУчасткаИФНСЮЛ,
	|	ЕСТЬNULL(ДополнительныеСведения.OKATO, """") КАК ОКАТО,
	|	ЕСТЬNULL(АдресныеОбъекты.КодКЛАДР, """") КАК КодКЛАДР
	|ИЗ
	|	РегистрСведений.ЗемельныеУчастки КАК ЗемельныеУчастки
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеАдресныеСведения КАК ДополнительныеСведения
	|		ПО (ДополнительныеСведения.Идентификатор = ЗемельныеУчастки.ДополнительныеАдресныеСведения)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|		ПО (АдресныеОбъекты.Идентификатор = ЗемельныеУчастки.АдресныйОбъект)
	|ГДЕ
	|	ЗемельныеУчастки.АдресныйОбъект = &АдресныйОбъект";

	Запрос.УстановитьПараметр("АдресныйОбъект", ИдентификаторАдресногоОбъекта);
	Запись = Запрос.Выполнить().Выбрать();

	Пока Запись.Следующий() Цикл
		Если ЗначениеЗаполнено(Запись.Участки) Тогда
			Описание = Запись.Участки.Получить();
			Если ЗначениеЗаполнено(Описание) Тогда
				ИзвлечьСписокЗемельныхУчастков(Описание, СтрокаПоиска, ВариантыЗемельныхУчастков, Запись,
					ТочноеСовпадение);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

// Вспомогательные

Функция ОбрезанноеНазвание(ИсходноеНазвание, ВырезаемаяПодстрока)
	
	ПозицияВырезки = СтрНайти(ВРег(ИсходноеНазвание), ВРег(ВырезаемаяПодстрока));

	ОбрезаннаяСтрока = ИсходноеНазвание;

	Если ПозицияВырезки > 0 Тогда
		ОбрезаннаяСтрока = Лев(ИсходноеНазвание, ПозицияВырезки - 1)
			+ Сред(ИсходноеНазвание, ПозицияВырезки + СтрДлина(ВырезаемаяПодстрока));
	КонецЕсли;

	Возврат СокрЛП(ОбрезаннаяСтрока);

КонецФункции

#КонецОбласти

#Область АдресныйКлассификаторВМоделиСервиса

// Регистрирует обработчики поставляемых данных за день и за все время.
//
// Параметры:
//     Обработчики - ТаблицаЗначений - таблица для добавления обработчиков. Содержит колонки:
//       * ВидДанных - Строка - код вида данных, обрабатываемый обработчиком.
//       * КодОбработчика - Строка - будет использоваться при восстановлении обработки данных после сбоя.
//       * Обработчик - ОбщийМодуль - модуль, содержащий экспортные  процедуры:
//                                          ДоступныНовыеДанные(Дескриптор, Загружать) Экспорт  
//                                          ОбработатьНовыеДанные(Дескриптор, ПутьКФайлу) Экспорт
//                                          ОбработкаДанныхОтменена(Дескриптор) Экспорт
//
Процедура ЗарегистрироватьОбработчикиПоставляемыхДанных(Знач Обработчики)

	Обработчик = Обработчики.Добавить();
	Обработчик.ВидДанных = "ГАР";
	Обработчик.КодОбработчика = "ГАР";
	Обработчик.Обработчик = АдресныйКлассификаторСлужебный;

КонецПроцедуры

Функция ПараметрыАдресногоКлассификатора()

	Возврат Новый Структура("Версия, Регион");

КонецФункции

Функция ПараметрыВерсииИзФайла(Знач Дескриптор)

	ПараметрыВерсии =  ПараметрыАдресногоКлассификатора();

	ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
	Для Каждого Характеристика Из Дескриптор.Properties.Property Цикл
		Если Характеристика.Code = "Регион" Тогда
			ПараметрыВерсии.Регион = ОписаниеТипаЧисло.ПривестиЗначение(Характеристика.Value);
		ИначеЕсли Характеристика.Code = "Версия" Тогда
			ПараметрыВерсии.Версия = ОписаниеТипаЧисло.ПривестиЗначение(Характеристика.Value);
		КонецЕсли;
	КонецЦикла;

	Возврат ПараметрыВерсии;

КонецФункции

Функция ОписаниеПоследнейЗагрузкиАдресногоКлассификатора(Знач КодРегиона)

	ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
	Результат = ПараметрыАдресногоКлассификатора();
	Запрос = Новый Запрос;

	Запрос.УстановитьПараметр("КодСубъектаРФ", КодРегиона);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ЗагруженныеВерсииАдресныхСведений.Версия,
	|	ЗагруженныеВерсииАдресныхСведений.КодСубъектаРФ КАК Регион
	|ИЗ
	|	РегистрСведений.ЗагруженныеВерсииАдресныхСведений КАК ЗагруженныеВерсииАдресныхСведений
	|ГДЕ
	|	ЗагруженныеВерсииАдресныхСведений.КодСубъектаРФ = &КодСубъектаРФ";

	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Результат.Версия = ОписаниеТипаЧисло.ПривестиЗначение(Выборка.Версия);
		Результат.Регион = Выборка.Регион;
	КонецЕсли;

	Возврат Результат;

КонецФункции

Функция ПроверитьНаличиеНовыхДанных(Знач Дескриптор)

	ПараметрыНовыхДанных = ПараметрыВерсииИзФайла(Дескриптор);
	Если ПараметрыНовыхДанных.Версия = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	Если Не ЗначениеЗаполнено(ПараметрыНовыхДанных.Регион) Тогда
		Возврат Истина;
	КонецЕсли;

	ПараметрыТекущихДанных = ОписаниеПоследнейЗагрузкиАдресногоКлассификатора(ПараметрыНовыхДанных.Регион);
	Если ПараметрыТекущихДанных.Версия = Неопределено Или ПараметрыНовыхДанных.Версия > ПараметрыТекущихДанных.Версия Тогда
		Возврат Истина;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

Процедура ОбработатьАдресныйКлассификатор(Знач Дескриптор, Знач ПутьКФайлу)

	КаталогФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ПолучитьИмяВременногоФайла());

	Попытка
		ЧтениеZIP = Новый ЧтениеZipФайла(ПутьКФайлу);
		ЧтениеZIP.ИзвлечьВсе(КаталогФайлов, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
		ЧтениеZIP.Закрыть();
		
		// Загружаем только то, что передано в файлах.
		СубъектыРФ = Новый Массив;
		ТипЧисло   = Новый ОписаниеТипов("Число");
		ОписаниеФайлов = Новый Массив;

		Для Каждого Файл Из НайтиФайлы(КаталогФайлов, "??.ZIP") Цикл
			КодРегиона = ТипЧисло.ПривестиЗначение(Лев(Файл.Имя, 2));
			Если КодРегиона > 0 Тогда
				СубъектыРФ.Добавить(КодРегиона);
			КонецЕсли;
			ОписаниеФайлов.Добавить(Новый Структура("Имя, Хранение", Файл.ПолноеИмя, Файл.ПолноеИмя));
		КонецЦикла;

		Если СубъектыРФ.Количество() > 0 Тогда

			ПараметрыЗагрузки = ПараметрыЗагрузкиКлассификатораАдресов();
			ПараметрыЗагрузки.ЗагружатьИсториюАдресов = Ложь;
			ПараметрыЗагрузки.ЗагружатьПорциями       = Истина;
			ПараметрыЗагрузки.ОповещатьОПрогрессе     = Ложь;

			ЗагрузитьКлассификаторАдресовПоставляемыеДанные(СубъектыРФ, ОписаниеФайлов, ПараметрыЗагрузки);

		КонецЕсли;

	Исключение
		ФайловаяСистема.УдалитьВременныйФайл(КаталогФайлов);
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура УстановкаТипаКузбассКемеровскойОбластиКакВГАР(КонтактнаяИнформацияПоПолям)
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Если СтрНайти(ВРег(КонтактнаяИнформацияПоПолям.area), ВРег("Кемеровская область")) > 0 
	 Или СтрНайти(ВРег(КонтактнаяИнформацияПоПолям.area), ВРег(ИсторическоеНаименованиеКемеровскойОбласти())) > 0 Тогда
		
		КонтактнаяИнформацияПоПолям.area      = "Кемеровская область - Кузбасс";
		КонтактнаяИнформацияПоПолям.areaType  = "обл";
		КонтактнаяИнформацияПоПолям.areaValue = КонтактнаяИнформацияПоПолям.area;
	КонецЕсли;
	// АПК: 1297-вкл
КонецПроцедуры

Функция НаименованиеРегионаБезТипа(Наименование)
	// АПК: 1297-выкл Данные адресного классификатора, не локализуются
	Возврат СтрНачинаетсяС(ВРег(Наименование), ВРег("Ханты-Мансийский Автономный округ - Югра")); // @Non-NLS-1
	// АПК: 1297-вкл
КонецФункции

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейсФоновыеОперацииСКлассификатором

#Область ЗагрузкаАдресногоКлассификатора

Процедура ЗагрузкаРегионаАдресногоКлассификатораССайта(ОписаниеСубъектаРФ, ПараметрыЗагрузки) Экспорт

	КодСубъекта = ОписаниеСубъектаРФ.Значение;
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		Возврат;
	КонецЕсли;

	УстановитьПривилегированныйРежим(Истина);
	Авторизация = ПараметрыАутентификацииНаСайте();
	УстановитьПривилегированныйРежим(Ложь);

	ВременныйКаталог = ПараметрыЗагрузки.КаталогФайлов;

	КодыСубъектовДляЗагрузки = Новый Массив;
	ОписаниеФайлов           = Новый Массив;

	ПараметрыПолучения = Новый Структура;
	Если Авторизация <> Неопределено Тогда
		ПараметрыПолучения.Вставить("Пользователь", Авторизация.Логин);
		ПараметрыПолучения.Вставить("Пароль", Авторизация.Пароль);
	КонецЕсли;

	ВсеВерсии = ДоступныеВерсииАдресныхСведений();
	ОписаниеРегиона = ВсеВерсии.Найти(КодСубъекта, "КодСубъектаРФ");
	Если ОписаниеРегиона = Неопределено Тогда
		// Возможно устаревший регион, не ошибка.
		Возврат;
	КонецЕсли;

	ФайлРегиона = АдресИнтернетаВключаяПорт(ОписаниеРегиона.Адрес);
	ПутьДляСохранения = ВременныйКаталог + ВРег(ФайлРегиона.ИмяФайла);

	ПараметрыПолучения.Вставить("ПутьДляСохранения", ПутьДляСохранения);

	ФайлПолучен = ПолучитьФайлИзИнтернета(ОписаниеРегиона, ВременныйКаталог, ПараметрыПолучения, ФайлРегиона.ИмяФайла);
	Если Не ФайлПолучен.Статус Тогда
		//  2 попытка получения файла
		Если Не ФайлСуществует(ВременныйКаталог) Тогда
			СоздатьКаталог(ВременныйКаталог);
		КонецЕсли;
		ФайлПолучен = ПолучитьФайлИзИнтернета(ОписаниеРегиона, ВременныйКаталог, ПараметрыПолучения,
			ФайлРегиона.ИмяФайла);
		Если Не ФайлПолучен.Статус Тогда
			ВызватьИсключение ФайлПолучен.СообщениеОбОшибке;
		КонецЕсли;

	КонецЕсли;

	КодыСубъектовДляЗагрузки.Добавить(КодСубъекта);
	ОписаниеФайлов.Добавить( Новый Структура("Имя, Хранение", ПутьДляСохранения, ПутьДляСохранения));

	ЗагрузитьДанныеКлассификатораАдресовИзФайла(КодСубъекта, ОписаниеФайлов, ПараметрыЗагрузки);

КонецПроцедуры

Функция ПолучитьФайлИзИнтернета(ОписаниеРегиона, Знач ВременныйКаталог, ПараметрыПолучения, ИмяФайла)

	Результат = СведенияОПолученииФайла();
	ПутьДляСохранения = ПараметрыПолучения.ПутьДляСохранения;
	МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
	ЗагруженныйФайл = МодульПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(ОписаниеРегиона.Адрес, ПараметрыПолучения);

	Если Не ЗагруженныйФайл.Статус Тогда
		ФайловаяСистема.УдалитьВременныйФайл(ВременныйКаталог);
		Результат.СообщениеОбОшибке = ЗагруженныйФайл.СообщениеОбОшибке;
		Возврат Результат;
	КонецЕсли;

	Если Не ФайлСуществует(ПутьДляСохранения) Тогда
		Результат.СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось загрузить файл %1. Загрузка адресных сведений прервана.
				 |Техническая информация: %2'"), ИмяФайла, ПутьДляСохранения);
	Иначе
		Результат.Статус = Истина;
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Статус - Булево
//   * СообщениеОбОшибке - Строка
//
Функция СведенияОПолученииФайла()

	Результат = Новый Структура;
	Результат.Вставить("Статус", Ложь);
	Результат.Вставить("СообщениеОбОшибке", "");

	Возврат Результат;

КонецФункции

Процедура ЗагрузитьДанныеКлассификатораАдресовИзФайла(СубъектРФ, ОписаниеФайлов, ПараметрыЗагрузки) Экспорт

	ДатаЗагрузки = ПараметрыЗагрузки.ДатаЗагрузки;

	Если ТипЗнч(ОписаниеФайлов) = Тип("Строка") Тогда
		// Файлы уже подготовлены
		КаталогФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ОписаниеФайлов);
	Иначе
		КаталогФайлов = ИзвлечьФайлыВКаталог(ОписаниеФайлов, ПараметрыЗагрузки.КаталогФайлов);
	КонецЕсли;

	КаталогФайлов = КаталогФайлов + Формат(СубъектРФ, "ЧЦ=2; ЧВН=") + ПолучитьРазделительПутиСервера();

	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Примечание,,,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Загрузка региона %1 из %2'"), СубъектРФ, КаталогФайлов));

	Попытка

		СлужебныеАдресныеСведения = СлужебныеАдресныеСведения(КаталогФайлов);
		ОбновитьСлужебныеАдресныеСведения(СлужебныеАдресныеСведения);

		НаименованиеРегиона = АдресныйКлассификатор.НаименованиеРегионаПоКоду(СубъектРФ);

		ДлительныеОперации.СообщитьПрогресс(0, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
			"ru = 'Загружается %1'"), НаименованиеРегиона));

		Попытка

			ЗагрузитьАдресныеСведенияПоРегиону(СубъектРФ, КаталогФайлов, ПараметрыЗагрузки);
				
				// Ставим версию данных загрузки региона.
			УстановитьИнформациюОЗагрузкеВерсии(СубъектРФ, СлужебныеАдресныеСведения.Версия,
				СлужебныеАдресныеСведения.ДатаВерсии, ДатаЗагрузки);

		Исключение
				
				// Во время загрузки возникла ошибка, очищаем частично загруженные данные.
			КодыСубъектаРФ = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СубъектРФ);

			ОчиститьКлассификаторАдресов(КодыСубъектаРФ);
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,,
			
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось загрузить адресные сведения субъекта РФ: %1 %2
							   |по причине: %3'"),
					СубъектРФ,
					НаименованиеРегиона,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
			
			ВызватьИсключение;
			
		КонецПопытки;
			
		// 4. Загружаем сокращения адресов.
		// Эти данные будут нужны при разборах адреса из строки.
		ОбновитьАдресныеСокращения(КаталогФайлов);

		// 5. Очищаем временный каталог.
		УдалитьФайлыРегиона(КаталогФайлов);

	Исключение
		
		// Очищаем временный каталог.

		УдалитьФайлыРегиона(КаталогФайлов);
		ВызватьИсключение;

	КонецПопытки;

КонецПроцедуры

// Загрузка всех данных классификатора адресов (поставляемые данные)
//
// Параметры:
//    КодыСубъектовРФ - Массив         - содержит числовые коды регионов-субъектов для загрузки.
//
//    ОписаниеФайлов  - Строка
//                    - Массив - каталог на сервере, в котором находятся файлы данных. Ожидается, что имена
//                      файлов будут в верхнем регистре.
//                               Массив элементов типа ОписаниеПередаваемогоФайла или структур с полями:
//                                           * Имя      - Строка - имя или полное имя передаваемого файла.
//                                           * Хранение - ДвоичныеДанные
//                                                      - Строка - описание хранения файла. Строка
//                                                        может быть путем на файловой системе или адресом во временном
//                                                        хранилище.
//    ОповещатьОПрогрессе - Булево      - флаг оповещения о прогрессе (см ДлительныеОперации.СообщитьПрогресс).
//
Процедура ЗагрузитьКлассификаторАдресовПоставляемыеДанные(КодыСубъектовРФ, ОписаниеФайлов, ПараметрыЗагрузки)

	ДатаЗагрузки = ТекущаяУниверсальнаяДата();

	Если ТипЗнч(ОписаниеФайлов) = Тип("Строка") Тогда
		// Файлы уже подготовлены
		КаталогФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ОписаниеФайлов);
		КаталогОбщихАдресныхСведений =  КаталогФайлов;
	Иначе
		КаталогФайлов = ИзвлечьФайлыВКаталог(ОписаниеФайлов);
		Если ТипЗнч(КодыСубъектовРФ) = Тип("Массив") И КодыСубъектовРФ.Количество() > 0 Тогда
			КаталогОбщихАдресныхСведений = КаталогФайлов
				+ Формат(КодыСубъектовРФ[0], "ЧЦ=2; ЧВН=")
				+ ПолучитьРазделительПутиСервера();
		Иначе
			Возврат;
		КонецЕсли;
	КонецЕсли;

	Попытка

		СлужебныеАдресныеСведения = СлужебныеАдресныеСведения(КаталогОбщихАдресныхСведений);
		ОбновитьСлужебныеАдресныеСведения(СлужебныеАдресныеСведения);
		
		// 2. Все заказанные субъекты
		ВсегоСубъектов = КодыСубъектовРФ.Количество();
		НомерПоПорядку = 0;

		Для Каждого СубъектРФ Из КодыСубъектовРФ Цикл

			НаименованиеРегиона = АдресныйКлассификатор.НаименованиеРегионаПоКоду(СубъектРФ);
			НомерПоПорядку      = НомерПоПорядку + 1;

			Если ПараметрыЗагрузки.ОповещатьОПрогрессе Тогда

				ОсталосьДляЗагрузки = ВсегоСубъектов - НомерПоПорядку;
				ОповеститьОПрогрессе(НаименованиеРегиона, СубъектРФ, ОсталосьДляЗагрузки);

			КонецЕсли;

			Попытка

				КаталогФайловРегиона = КаталогФайлов + Формат(СубъектРФ, "ЧЦ=2; ЧВН=")
					+ ПолучитьРазделительПутиСервера();
				ЗагрузитьАдресныеСведенияПоРегиону(СубъектРФ, КаталогФайловРегиона, ПараметрыЗагрузки);
				
				// Ставим версию данных загрузки региона.
				УстановитьИнформациюОЗагрузкеВерсии(СубъектРФ, СлужебныеАдресныеСведения.Версия,
					СлужебныеАдресныеСведения.ДатаВерсии, ДатаЗагрузки);

			Исключение
				
				// Во время загрузки возникла ошибка, очищаем частично загруженные данные.
				КодыСубъектаРФ = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СубъектРФ);

				//@skip-check query-in-loop - штучный легкий запрос, только в исключительной ситуации для отката неудачной загрузки.
				ОчиститьКлассификаторАдресов(КодыСубъектаРФ); // Очистка только если во время загрузки адресных сведений возникла ошибка.
				
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,,
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не удалось загрузить адресные сведения субъекта РФ: %1 %2
								   |по причине: %3'"),
						СубъектРФ,
						НаименованиеРегиона,
						ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
				
				ВызватьИсключение;
				
			КонецПопытки;

		КонецЦикла;
		
		// 4. Загружаем сокращения адресов.
		// Эти данные будут нужны при разборах адреса из строки.
		ОбновитьАдресныеСокращения(КаталогОбщихАдресныхСведений);

		// 5. Очищаем временный каталог.
		ФайловаяСистема.УдалитьВременныйФайл(КаталогФайлов);

	Исключение
		
		// Очищаем временный каталог.
		ФайловаяСистема.УдалитьВременныйФайл(КаталогФайлов);
		ВызватьИсключение;

	КонецПопытки;

КонецПроцедуры

// Обработчик фоновой очистки
//
Процедура ФоновоеЗаданиеОчисткиКлассификатораАдресов(Параметры, АдресРезультата) Экспорт

	ОчиститьКлассификаторАдресов(Параметры[0]);

КонецПроцедуры

// Проверяет наличие в конфигурации подсистемы ПолучениеФайловИзИнтернета для определения возможности
// обновлений адресного классификатора через интернет.
// 
// Возвращаемое значение:
//  Булево - доступна загрузка адресных сведений из интернет
//
Функция ДоступнаЗагрузкаАдресныхСведенийИзИнтернет() Экспорт
	Возврат ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета");
КонецФункции

// Проверяет наличие обновлений адресного классификатора на веб сервере
// для тех объектов, которые ранее уже загружались.
//
// Возвращаемое значение:
//   ТаблицаЗначений - описание добавленных и измененных субъектов. Содержит Колонки:
//     * КодСубъектаРФ      - Число                   - код субъекта РФ.
//     * Наименование       - Строка                  - наименование субъекта РФ.
//     * Сокращение         - Строка                  - сокращение субъекта РФ.
//     * Индекс             - Число                   - почтовый индекс.
//     * Идентификатор      - УникальныйИдентификатор - идентификатор субъекта.
//     * Адрес              - Строка                  - адрес для скачивания файла данных региона.
//     * ДоступноОбновление - Булево                  - флаг доступности обновления для данного региона.
//     * Загружено          - Булево                  - флаг того, что данные хоть раз загружались.
//     * ДатаОбновления     - Дата                    - дата обновления адресных сведений.
//
Функция ДоступныеВерсииАдресныхСведений(ПараметрыВыгрузки = Неопределено, АдресВоВременномХранилище = Неопределено) Экспорт

	Результат = Новый ТаблицаЗначений;

	ТипСтрока = Новый ОписаниеТипов("Строка");
	ТипЧисло  = Новый ОписаниеТипов("Число");
	ТипБулево = Новый ОписаниеТипов("Булево");
	ТипДата   = Новый ОписаниеТипов("Дата");
	Колонки   = Результат.Колонки;

	Колонки.Добавить("КодСубъектаРФ", ТипЧисло);
	Колонки.Добавить("ПолноеНаименование", ТипСтрока);
	Колонки.Добавить("Наименование", ТипСтрока);
	Колонки.Добавить("Сокращение", ТипСтрока);
	Колонки.Добавить("Индекс", ТипЧисло);
	Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Колонки.Добавить("Адрес", ТипСтрока);
	Колонки.Добавить("ДоступноОбновление", ТипБулево);
	Колонки.Добавить("Загружено", ТипБулево);
	Колонки.Добавить("ДатаОбновления", ТипДата);

	Результат.Индексы.Добавить("КодСубъектаРФ");

	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		Возврат Результат;
	КонецЕсли;

	МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");

	АдресОписания = АдресИнтернетаВключаяПорт(АдресФайлаОписанияДоступныхВерсий());
	РезультатПолученияФайла = МодульПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(АдресОписания.Адрес);
	Если Не РезультатПолученияФайла.Статус Тогда
		Возврат Результат;
	КонецЕсли;
	
	// Получен zip, внутри которого xml.
	КаталогДляРаспаковки = ПолучитьИмяВременногоФайла();
	Архив = Новый ЧтениеZipФайла(РезультатПолученияФайла.Путь);
	Архив.ИзвлечьВсе(КаталогДляРаспаковки);
	ФайлОписания = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогДляРаспаковки) + "version.xml";

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ФайлОписания);
	ДоступныеДанные = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип(ПространствоИмен(), "Publications"));

	ЧтениеXML.Закрыть();
	ФайловаяСистема.УдалитьВременныйФайл(КаталогДляРаспаковки);

	ДатаПоследнейВерсии = '00000000';
	ПоследняяПубликация = Неопределено;

	Для Каждого Публикация Из ДоступныеДанные.ПолучитьСписок("Publication") Цикл
		Если Публикация.UpdateDate > ДатаПоследнейВерсии Тогда
			ДатаПоследнейВерсии = Публикация.UpdateDate;
			ПоследняяПубликация = Публикация;
		КонецЕсли;
	КонецЦикла;

	Если ПоследняяПубликация = Неопределено Тогда
		// Нет данных совсем
		Возврат Результат;
	КонецЕсли;
	
	// Сравниваем то что в регистре, и то что прочитали.
	ТекущиеСубъекты = СведенияОЗагрузкеСубъектовРФ();

	Для Каждого ЗаписьРегиона Из ПоследняяПубликация.ПолучитьСписок("Region") Цикл
		Идентификатор = УникальныйИдентификаторИзДвоичныхДанных(ЗаписьРегиона.AOGUID);
		ТекущийСубъект = ТекущиеСубъекты.Найти(Идентификатор, "Идентификатор");

		Если ТекущийСубъект = Неопределено Тогда
			Продолжить;
		КонецЕсли;

		СтрокаРегиона = Результат.Добавить();
		СтрокаРегиона.КодСубъектаРФ = ЗаписьРегиона.REGIONCODE;
		СтрокаРегиона.ПолноеНаименование =  ЗаписьРегиона.NAME;
		СтрокаРегиона.Наименование  = ЗаписьРегиона.FORMALNAME;
		СтрокаРегиона.Сокращение    = ЗаписьРегиона.SHORTNAME;
		СтрокаРегиона.Индекс        = ЗаписьРегиона.POSTALCODE;
		СтрокаРегиона.Идентификатор = Идентификатор;
		СтрокаРегиона.Адрес         = ЗаписьРегиона.Url;
		СтрокаРегиона.Загружено     = ТекущийСубъект <> Неопределено И ТекущийСубъект.Загружено;
		СтрокаРегиона.ДатаОбновления = ДатаПоследнейВерсии;

		Если ЗначениеЗаполнено(ТекущийСубъект.ДатаВерсии) Тогда
			СтрокаРегиона.ДоступноОбновление = ТекущийСубъект = Неопределено   // Новый регион

				Или ТекущийСубъект.ДатаВерсии < ДатаПоследнейВерсии            // Обновленный регион

				Или (ТекущийСубъект.КодСубъектаРФ <> ЗаписьРегиона.REGIONCODE);// Обновленные данные существующего субъекта.
		КонецЕсли;
	КонецЦикла;

	Если АдресВоВременномХранилище <> Неопределено Тогда
		Ответ = Новый Структура("Отказ, Таблица");
		Ответ.Отказ = Ложь;
		Ответ.Таблица = Результат;
		ПоместитьВоВременноеХранилище(Ответ, АдресВоВременномХранилище);
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Вычитываем справочную информацию и информацию о версии.
//
Функция СлужебныеАдресныеСведения(КаталогФайлов)

	Набор = РегистрыСведений.СлужебныеАдресныеСведения.СоздатьНаборЗаписей();
	Сведения = Набор.ВыгрузитьКолонки("Тип, Идентификатор, Ключ, Значение");
	Сведения.Индексы.Добавить("Тип, Идентификатор, Ключ");

	Результат = Новый Структура("Сведения", Сведения);
	ТекущаяЗапись = Неопределено;
	
	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(Неопределено, КаталогФайлов, "ADDRSTATUS", "AddressStatuses");
	
	Если ФайлЗагрузки = Неопределено Тогда
		Возврат НСтр("ru = 'В загруженных данных отсутствует файл адресных сведений.'");
	КонецЕсли;
	
	Попытка
		
		ТекущаяЗапись =  ФайлЗагрузки.ФайлЧтения;
		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
				Продолжить;
			КонецЕсли;

			ТипЗаписи = ТекущаяЗапись.ЗначениеАтрибута("TYPE");
			Значение  = ТекущаяЗапись.ЗначениеАтрибута("VALUE");

			Запись = Сведения.Добавить();

			Запись.Тип           = ТипЗаписи;
			Запись.Идентификатор = ТекущаяЗапись.ЗначениеАтрибута("ID");
			Запись.Ключ          = ТекущаяЗапись.ЗначениеАтрибута("KEY");
			Запись.Значение      = Значение;

		КонецЦикла;

		НенужныеСимволы = СтрСоединить(СтрРазделить(ФайлЗагрузки.ДатаВерсии, "0123456789"));
		ДатаВерсии = Дата(СтрСоединить(СтрРазделить(ФайлЗагрузки.ДатаВерсии, НенужныеСимволы)));

		Результат.Вставить("Версия", ФайлЗагрузки.Версия);
		Результат.Вставить("ДатаВерсии", ДатаВерсии);

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;

	КонецПопытки;

	Возврат Результат;

КонецФункции

// Возвращает описание параметров загрузки классификатора адресов
// 
// Возвращаемое значение:
//  Структура:
//   * ЗагружатьИсториюАдресов - Булево - если Истина, то будет загружена история адресных сведений. По умолчанию, Ложь.
//   * ДатаЗагрузки - Дата - дата, которая будет установлена как дата загрузки региона. 
//   * ЗагружатьПорциями - Булево - если Истина, то загрузка будет осуществляться порциями. По умолчанию, Ложь.
//   * ОповещатьОПрогрессе - Булево - если Истина, то передаваться сообщение о статусе загрузки. По умолчанию, Истина.
//
Функция ПараметрыЗагрузкиКлассификатораАдресов() Экспорт

	Результат = Новый Структура;
	Результат.Вставить("ЗагружатьИсториюАдресов", Ложь);
	Результат.Вставить("ДатаЗагрузки", ТекущаяДатаСеанса());
	Результат.Вставить("ОповещатьОПрогрессе", Истина);
	Результат.Вставить("КаталогФайлов", "");

	СистемнаяИнформация = Новый СистемнаяИнформация;
	ОперативнаяПамять = СистемнаяИнформация.ОперативнаяПамять / 1024; // Гб

	ЗагружатьПорциями = Ложь;
	Если ОперативнаяПамять < 4 
	   Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
	   Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86 
	   Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.MacOS_x86 Тогда
		ЗагружатьПорциями = Истина;
	КонецЕсли;
	Результат.Вставить("ЗагружатьПорциями", ЗагружатьПорциями);

	Возврат Результат;

КонецФункции

Процедура ЗагрузитьАдресныеСведенияПоРегиону(Знач СубъектРФ, Знач КаталогФайлов, ПараметрыЗагрузки)

	ЗагружатьОднимНабором = Не ПараметрыЗагрузки.ЗагружатьПорциями;
	ЗагрузитьАдресныеОбъекты(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором);
	ЗагрузитьИерархиюАдресов(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором, "МуниципальнаяИерархия");
	ЗагрузитьИерархиюАдресов(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором, "АдминистративнаяИерархия");
	ЗагрузитьДомаЗданияСтроения(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором);
	ЗагрузитьЗемельныеУчастки(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором);

	Если ПараметрыЗагрузки.ЗагружатьИсториюАдресов Тогда
		ЗагрузитьИсториюАдресныхОбъектов(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором);
		ЗагрузитьИерархиюАдресов(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором, "ИсторияМуниципальнойИерархии");
		ЗагрузитьИерархиюАдресов(СубъектРФ, КаталогФайлов, ЗагружатьОднимНабором, "ИсторияАдминистративнойИерархии");
		ЗагрузитьПричиныИзмененияАдреса(СубъектРФ, КаталогФайлов);
	КонецЕсли;

	ЗагрузитьДополнительныеСведения(СубъектРФ, КаталогФайлов, ПараметрыЗагрузки.ЗагружатьИсториюАдресов);

КонецПроцедуры

Процедура ЗагрузитьАдресныеОбъекты(КодСубъектаРФ, КаталогФайлов, ЗагружатьОднимНабором)
	
	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ADDROBJ", "AddressObjects");

	Если ФайлЗагрузки = Неопределено Тогда
		
		ВызватьИсключение
			НСтр("ru = 'Загрузка адресных сведений прервана.
			|В загружаемых файлах не найден файл с адресными сведениями.'");
			
	КонецЕсли;

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;
	Замещать = Истина;
	КоличествоЗаписейВНаборе = 0;
	РазмерПорции = МаксимальныйРазмерНабораЗаписей();

	Набор = РегистрыСведений.АдресныеОбъекты.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

	Попытка

		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
				Продолжить;
			КонецЕсли;

			Запись = Набор.Добавить();

			Запись.КодСубъектаРФ = КодСубъектаРФ;
			Запись.Уровень       = ТекущаяЗапись.ЗначениеАтрибута("LEVEL");
			Запись.Идентификатор = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("OBJECTGUID"));

			Запись.Наименование               = ТекущаяЗапись.ЗначениеАтрибута("NAME");
			Запись.ТипОбъекта                 = ТекущаяЗапись.ЗначениеАтрибута("TYPENAME");
			Запись.ДополнительныеАдресныеСведения = УникальныйИдентификаторИзСтроки64(
				ТекущаяЗапись.ЗначениеАтрибута("EXTRAGUID"));
			Запись.КодКЛАДР                   = ТекущаяЗапись.ЗначениеАтрибута("CODE");

			Если ЗагружатьОднимНабором Тогда
				Продолжить;
			КонецЕсли;

			Если КоличествоЗаписейВНаборе < РазмерПорции Тогда
				КоличествоЗаписейВНаборе = КоличествоЗаписейВНаборе + 1;
				Продолжить;
			КонецЕсли;

			ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
			Замещать = Ложь;
			КоличествоЗаписейВНаборе = 0;

			Набор = РегистрыСведений.АдресныеОбъекты.СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

		КонецЦикла;

		ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ЗагрузитьИерархиюАдресов(КодСубъектаРФ, КаталогФайлов, ЗагружатьОднимНабором, ОбъектЗагрузки)

	ФайлЗагрузки = Неопределено;
	
	Если ОбъектЗагрузки = "МуниципальнаяИерархия" Тогда
		ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ADDRMUN", "ObjectRelations");
	ИначеЕсли ОбъектЗагрузки = "АдминистративнаяИерархия" Тогда
		ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ADDRADM", "ObjectRelations");
	ИначеЕсли ОбъектЗагрузки = "ИсторияМуниципальнойИерархии" Тогда
		ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ARCHMUN", "ArchiveRelations");
	ИначеЕсли ОбъектЗагрузки = "ИсторияАдминистративнойИерархии" Тогда
		ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ARCHADM", "ArchiveRelations");
	КонецЕсли;

	Если ФайлЗагрузки = Неопределено Тогда
		
		ВызватьИсключение 
			НСтр("ru = 'Загрузка адресных сведений прервана.
			|В загружаемых файлах не найден файл с адресными сведениями.'");
		
	КонецЕсли;

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;
	Замещать = Истина;
	КоличествоЗаписейВНаборе = 0;
	РазмерПорции = МаксимальныйРазмерНабораЗаписей();

	Набор = РегистрыСведений[ОбъектЗагрузки].СоздатьНаборЗаписей(); // РегистрСведений.ИсторияМуниципальнойИерархии
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	
	ЭтоИстория = СтрНачинаетсяС(ОбъектЗагрузки, "История");
	
	Попытка
		
		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
				Продолжить;
			КонецЕсли;

			Запись = Набор.Добавить(); // РегистрСведенийЗапись.ИсторияМуниципальнойИерархии
			
			Запись.КодСубъектаРФ = КодСубъектаРФ;
			Запись.Идентификатор = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("OBJECTGUID"));
			Запись.РодительскийИдентификатор = УникальныйИдентификаторИзСтроки64(
				ТекущаяЗапись.ЗначениеАтрибута("PARENTOBJECTGUID"));
			
			Если ЭтоИстория Тогда
				Запись.ИдентификаторЗаписи = ТекущаяЗапись.ЗначениеАтрибута("AOID");
			КонецЕсли;
			
			Если ЗагружатьОднимНабором Тогда
				Продолжить;
			КонецЕсли;

			Если КоличествоЗаписейВНаборе < РазмерПорции Тогда
				КоличествоЗаписейВНаборе = КоличествоЗаписейВНаборе + 1;
				Продолжить;
			КонецЕсли;

			ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
			Замещать = Ложь;
			КоличествоЗаписейВНаборе = 0;

			Набор = РегистрыСведений[ОбъектЗагрузки].СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

		КонецЦикла;

		ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ЗагрузитьДомаЗданияСтроения(КодСубъектаРФ, КаталогФайлов, ЗагружатьОднимНабором)

	Сжатие = Новый СжатиеДанных(9);
	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "HOUSE", "Houses");

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;

	Набор = РегистрыСведений.ДомаЗданияСтроения.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

	Замещать = Истина;
	КоличествоЗаписейВНаборе = 0;
	РазмерПорции = МаксимальныйРазмерНабораЗаписей();

	Попытка

		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента 
			   Или ПустаяСтрока(ТекущаяЗапись.ЗначениеАтрибута("PARENTOBJECTGUID")) Тогда
				Продолжить;
			КонецЕсли;

			Запись = Набор.Добавить();

			Запись.КодСубъектаРФ  = КодСубъектаРФ;
			Запись.АдресныйОбъект = УникальныйИдентификаторИзСтроки64(
				ТекущаяЗапись.ЗначениеАтрибута("PARENTOBJECTGUID"));
			Запись.ДополнительныеАдресныеСведения = УникальныйИдентификаторИзСтроки64(
				ТекущаяЗапись.ЗначениеАтрибута("EXTRAGUID"));
			Запись.Строения = Новый ХранилищеЗначения(ТекущаяЗапись.ЗначениеАтрибута("BUILDINGS"), Сжатие);

			Если ЗагружатьОднимНабором Тогда
				Продолжить;
			КонецЕсли;

			Если КоличествоЗаписейВНаборе < РазмерПорции Тогда
				КоличествоЗаписейВНаборе = КоличествоЗаписейВНаборе + 1;
				Продолжить;
			КонецЕсли;

			ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
			Замещать = Ложь;
			КоличествоЗаписейВНаборе = 0;

			Набор = РегистрыСведений.ДомаЗданияСтроения.СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

		КонецЦикла;

		ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ЗагрузитьЗемельныеУчастки(КодСубъектаРФ, КаталогФайлов, ЗагружатьОднимНабором)

	Сжатие = Новый СжатиеДанных(9);
	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "STEAD", "Steads");

	Если ФайлЗагрузки = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;

	Набор = РегистрыСведений.ЗемельныеУчастки.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

	Замещать = Истина;
	КоличествоЗаписейВНаборе = 0;
	РазмерПорции = МаксимальныйРазмерНабораЗаписей();

	Попытка

		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
				Продолжить;
			КонецЕсли;

			Запись = Набор.Добавить();

			Запись.КодСубъектаРФ  = КодСубъектаРФ;
			Запись.АдресныйОбъект = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("PARENTGUID"));
			Запись.ДополнительныеАдресныеСведения = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута(
				"EXTRAGUID"));
			Запись.Участки = Новый ХранилищеЗначения(ТекущаяЗапись.ЗначениеАтрибута("NUMBER"), Сжатие);

			Если ЗагружатьОднимНабором Тогда
				Продолжить;
			КонецЕсли;

			Если КоличествоЗаписейВНаборе < РазмерПорции Тогда
				КоличествоЗаписейВНаборе = КоличествоЗаписейВНаборе + 1;
				Продолжить;
			КонецЕсли;

			ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
			Замещать = Ложь;
			КоличествоЗаписейВНаборе = 0;

			Набор = РегистрыСведений.ЗемельныеУчастки.СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

		КонецЦикла;

		ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;

	КонецПопытки;

КонецПроцедуры

Процедура ЗагрузитьДополнительныеСведения(КодСубъектаРФ, КаталогФайлов, ЗагружатьИсториюИзменений)

	Набор = РегистрыСведений.ДополнительныеАдресныеСведения.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ЗагрузитьВНаборДополнительныеСведенияИзФайла(Набор, "EXTRAACT", КаталогФайлов, КодСубъектаРФ);

	Если ЗагружатьИсториюИзменений Тогда
		ЗагрузитьВНаборДополнительныеСведенияИзФайла(Набор, "EXTRAHIS", КаталогФайлов, КодСубъектаРФ);
	КонецЕсли;

	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ЗагрузитьВНаборДополнительныеСведенияИзФайла(Набор, Знач ИмяФайла, Знач КаталогФайлов, Знач КодСубъектаРФ)

	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, ИмяФайла, "AdditionalAddressInfo");

	Если ФайлЗагрузки = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;

	Пока ТекущаяЗапись.Прочитать() Цикл

		Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
			Продолжить;
		КонецЕсли;

		Запись = Набор.Добавить();

		Запись.КодСубъектаРФ          = КодСубъектаРФ;
		Запись.Идентификатор          = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("EXTRAGUID"));
		Запись.ПочтовыйИндекс         = ТекущаяЗапись.ЗначениеАтрибута("POSTALCODE");
		Запись.OKATO                  = ТекущаяЗапись.ЗначениеАтрибута("OKATO");
		Запись.ОКТМО                  = ТекущаяЗапись.ЗначениеАтрибута("OKTMO");
		Запись.ОКТМОБюджетополучателя = ТекущаяЗапись.ЗначениеАтрибута("OKTMOBUDGET");
		Запись.КодИФНСФЛ              = ТекущаяЗапись.ЗначениеАтрибута("IFNSFL");
		Запись.КодИФНСЮЛ              = ТекущаяЗапись.ЗначениеАтрибута("IFNSUL");
		Запись.КодУчасткаИФНСФЛ       = ТекущаяЗапись.ЗначениеАтрибута("TERRIFNSFL");
		Запись.КодУчасткаИФНСЮЛ       = ТекущаяЗапись.ЗначениеАтрибута("TERRIFNSUL");
	КонецЦикла;

	ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

КонецПроцедуры

Процедура ЗагрузитьИсториюАдресныхОбъектов(КодСубъектаРФ, КаталогФайлов, ЗагружатьОднимНабором)

	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ARCHOBJ", "ArchiveObjects");

	Если ФайлЗагрузки = Неопределено Тогда
		
		ВызватьИсключение 
			НСтр("ru = 'Загрузка адресных сведений прервана.
			|В загружаемых файлах не найден файл с адресными сведениями.'");
			
	КонецЕсли;

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;

	Замещать = Истина;
	КоличествоЗаписейВНаборе = 0;
	РазмерПорции = МаксимальныйРазмерНабораЗаписей();

	Набор = РегистрыСведений.ИсторияАдресныхОбъектов.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

	Попытка

		Пока ТекущаяЗапись.Прочитать() Цикл

			Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
				Продолжить;
			КонецЕсли;

			Запись = Набор.Добавить();

			Запись.КодСубъектаРФ = КодСубъектаРФ;
			Запись.Уровень       = ТекущаяЗапись.ЗначениеАтрибута("LEVEL");

			Запись.Идентификатор = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("AOID"));
			Запись.АдресныйОбъект = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("OBJECTGUID"));
			Запись.ДополнительныеАдресныеСведения = УникальныйИдентификаторИзСтроки64(
				ТекущаяЗапись.ЗначениеАтрибута("EXTRAGUID"));

			Запись.Наименование               = ТекущаяЗапись.ЗначениеАтрибута("NAME");
			Запись.ТипОбъекта                 = ТекущаяЗапись.ЗначениеАтрибута("TYPENAME");
			Запись.Операция                   = ТекущаяЗапись.ЗначениеАтрибута("OPERSTATUS");

			Если ЗначениеЗаполнено(ТекущаяЗапись.ЗначениеАтрибута("STARTDATE")) Тогда
				Запись.НачалоДействияЗаписи      = Дата(ТекущаяЗапись.ЗначениеАтрибута("STARTDATE"));
			КонецЕсли;

			Если ЗначениеЗаполнено(ТекущаяЗапись.ЗначениеАтрибута("ENDDATE")) Тогда
				Запись.ОкончаниеДействияЗаписи    = Дата(ТекущаяЗапись.ЗначениеАтрибута("ENDDATE"));
			КонецЕсли;

			Если ЗагружатьОднимНабором Тогда
				Продолжить;
			КонецЕсли;

			Если КоличествоЗаписейВНаборе < РазмерПорции Тогда
				КоличествоЗаписейВНаборе = КоличествоЗаписейВНаборе + 1;
				Продолжить;
			КонецЕсли;

			ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
			Замещать = Ложь;
			КоличествоЗаписейВНаборе = 0;

			Набор = РегистрыСведений.ИсторияАдресныхОбъектов.СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

		КонецЦикла;

		ОбновлениеИнформационнойБазы.ЗаписатьНаборЗаписей(Набор, Замещать);
		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

	Исключение

		ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ЗагрузитьПричиныИзмененияАдреса(КодСубъектаРФ, КаталогФайлов)

	Сжатие = Новый СжатиеДанных(9);

	Набор = РегистрыСведений.ПричиныИзмененияАдресныхСведений.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ФайлЗагрузки = ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, "ARCHDOCS", "RegulatoryDocs");

	Если ФайлЗагрузки = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ТекущаяЗапись =  ФайлЗагрузки.ФайлЧтения;
	Пока ТекущаяЗапись.Прочитать() Цикл

		Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
			Продолжить;
		КонецЕсли;

		Запись = Набор.Добавить();

		Запись.КодСубъектаРФ    = КодСубъектаРФ;
		Запись.Идентификатор    = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("DOCID"));
		Запись.ИзмененныйОбъект = УникальныйИдентификаторИзСтроки64(ТекущаяЗапись.ЗначениеАтрибута("OBJID"));
		Запись.СодержитОписание = ТекущаяЗапись.ЗначениеАтрибута("ISDESCR");
		Запись.Описание         = Новый ХранилищеЗначения(ТекущаяЗапись.ЗначениеАтрибута("DESCR"), Сжатие);

	КонецЦикла;

	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);
	ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

КонецПроцедуры

Процедура УстановитьИнформациюОЗагрузкеВерсии(КодСубъектаРФ, Версия, ДатаВерсии, ДатаЗагрузки)

	Набор = РегистрыСведений.ЗагруженныеВерсииАдресныхСведений.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);

	ОсновнаяЗапись = Набор.Добавить();
	ОсновнаяЗапись.КодСубъектаРФ = КодСубъектаРФ;
	ОсновнаяЗапись.Версия        = Версия;
	ОсновнаяЗапись.ДатаВерсии    = ДатаВерсии;
	ОсновнаяЗапись.ДатаЗагрузки  = ДатаЗагрузки;

	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура СброситьИнформациюОЗагрузкеВерсии(КодСубъектаРФ)

	Набор = РегистрыСведений.ЗагруженныеВерсииАдресныхСведений.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура УдалитьФайлыРегиона(КаталогФайлов)

	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Примечание,,,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Удаление файла региона: %1'"), КаталогФайлов));

	УдалитьФайлы(КаталогФайлов);
КонецПроцедуры

// Очистка данных классификатора адресов.
//
// Параметры:
//    КодыСубъектовРФ - Массив - содержит числовые коды регионов-субъектов для очистки.
//
Процедура ОчиститьКлассификаторАдресов(КодыСубъектовРФ)
	
	// Все заказанные субъекты
	ВсегоСубъектов = КодыСубъектовРФ.Количество();
	НомерПоПорядку = 0;
	
	СведенияОбРегионах = Новый Соответствие();
	Классификатор = РегистрыСведений.АдресныеОбъекты.КлассификаторСубъектовРФ();
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	АдресныеОбъекты.Идентификатор КАК Идентификатор,
	|	АдресныеОбъекты.КодСубъектаРФ КАК КодСубъектаРФ,
	|	АдресныеОбъекты.Наименование КАК Наименование,
	|	АдресныеОбъекты.ТипОбъекта КАК ТипОбъекта,
	|	АдресныеОбъекты.КодКЛАДР КАК КодКЛАДР,
	|	АдресныеОбъекты.ДополнительныеАдресныеСведения КАК ДополнительныеАдресныеСведения,
	|	АдресныеОбъекты.Уровень КАК Уровень
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|ГДЕ
	|	АдресныеОбъекты.Уровень = 1
	|	И АдресныеОбъекты.КодСубъектаРФ В (&КодыСубъектовРФ)";

	Запрос.УстановитьПараметр("КодыСубъектовРФ", КодыСубъектовРФ);
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();
	
	Для Каждого КодСубъектаРФ Из КодыСубъектовРФ Цикл
		
		СведенияОбРегионе =  РезультатЗапроса.Найти(КодСубъектаРФ, "КодСубъектаРФ");
		Если СведенияОбРегионе = Неопределено Тогда
			СведенияОбРегионе = Классификатор.Найти(КодСубъектаРФ, "КодСубъектаРФ");
		КонецЕсли;
		
		Если СведенияОбРегионе <> Неопределено Тогда
			СведенияОбРегионах.Вставить(КодСубъектаРФ, ОбщегоНазначения.СтрокаТаблицыЗначенийВСтруктуру(СведенияОбРегионе));
		КонецЕсли;
		
	КонецЦикла;

	Для Каждого СубъектРФ Из КодыСубъектовРФ Цикл

		НомерПоПорядку = НомерПоПорядку + 1;
		ДлительныеОперации.СообщитьПрогресс( , СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Очистка региона ""%1 - %2"" (осталось %3) ...'"),
				СубъектРФ,
				АдресныйКлассификатор.НаименованиеРегионаПоКоду(СубъектРФ),
				Формат(ВсегоСубъектов - НомерПоПорядку, "ЧН=")));

		НачатьТранзакцию();
		Попытка
			
			ОчиститьАдресныеОбъекты(СубъектРФ, СведенияОбРегионах.Получить(СубъектРФ));
			ОчиститьДомаЗданияСтроения(СубъектРФ);
			ОчиститьИсториюАдресныхОбъектов(СубъектРФ);
			ОчиститьЗемельныеУчастки(СубъектРФ);
			ОчиститьМуниципальнуюИерархиюАдресныхОбъектов(СубъектРФ);
			ОчиститьАдминистративнуюИерархиюАдресныхОбъектов(СубъектРФ);
			ОчиститьИсториюАдминистративнойИерархииАдресныхОбъектов(СубъектРФ);
			ОчиститьИсториюМуниципальнойИерархииАдресныхОбъектов(СубъектРФ);
			ОчиститьПричиныИзмененияАдреса(СубъектРФ);
			ОчиститьДополнительныеСведения(СубъектРФ);
			
			СброситьИнформациюОЗагрузкеВерсии(СубъектРФ);
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;

	КонецЦикла;
	
	ОчиститьУровниСокращенийАдресныхСведений();

КонецПроцедуры

Процедура ОчиститьАдресныеОбъекты(КодСубъектаРФ, СведенияОбРегионе)
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.АдресныеОбъекты");
	ЭлементБлокировки.УстановитьЗначение("КодСубъектаРФ", КодСубъектаРФ);
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка.Заблокировать();
		УстановитьПривилегированныйРежим(Истина);
		
		Набор = РегистрыСведений.АдресныеОбъекты.СоздатьНаборЗаписей();
		Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
		ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);
		
		Если СведенияОбРегионе <> Неопределено Тогда
			Набор = РегистрыСведений.АдресныеОбъекты.СоздатьНаборЗаписей();
			Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
			НоваяЗапись = Набор.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяЗапись, СведенияОбРегионе);
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);
		КонецЕсли;

		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ОчиститьДомаЗданияСтроения(КодСубъектаРФ)

	Набор = РегистрыСведений.ДомаЗданияСтроения.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьЗемельныеУчастки(КодСубъектаРФ)

	Набор = РегистрыСведений.ЗемельныеУчастки.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьМуниципальнуюИерархиюАдресныхОбъектов(КодСубъектаРФ)

	Набор = РегистрыСведений.МуниципальнаяИерархия.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьАдминистративнуюИерархиюАдресныхОбъектов(КодСубъектаРФ)

	Набор = РегистрыСведений.АдминистративнаяИерархия.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьИсториюМуниципальнойИерархииАдресныхОбъектов(КодСубъектаРФ)

	Набор = РегистрыСведений.ИсторияМуниципальнойИерархии.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьИсториюАдминистративнойИерархииАдресныхОбъектов(КодСубъектаРФ)

	Набор = РегистрыСведений.ИсторияАдминистративнойИерархии.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьДополнительныеСведения(КодСубъектаРФ)

	Набор = РегистрыСведений.ДополнительныеАдресныеСведения.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьИсториюАдресныхОбъектов(КодСубъектаРФ)

	Набор = РегистрыСведений.ИсторияАдресныхОбъектов.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьПричиныИзмененияАдреса(КодСубъектаРФ)

	Набор = РегистрыСведений.ПричиныИзмененияАдресныхСведений.СоздатьНаборЗаписей();
	Набор.Отбор.КодСубъектаРФ.Установить(КодСубъектаРФ);
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

Процедура ОчиститьУровниСокращенийАдресныхСведений()

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	АдресныеОбъекты.Уровень
	|ИЗ
	|	РегистрСведений.АдресныеОбъекты КАК АдресныеОбъекты
	|ГДЕ
	|	АдресныеОбъекты.Уровень > 1";

	РезультатЗапроса = Запрос.Выполнить().Выбрать();

	Если РезультатЗапроса.Следующий() Тогда
		Возврат;
	КонецЕсли;

	НачатьТранзакцию();

	Попытка

		БлокировкаДанных = Новый БлокировкаДанных;
		БлокировкаДанных.Добавить("РегистрСведений.УровниСокращенийАдресныхСведений");
		БлокировкаДанных.Заблокировать();
		
		// Т.к. адресный классификатор не содержит сведений, то очищаем таблицу адресных сведений.
		УровниСокращенийАдресныхСведений = РегистрыСведений.УровниСокращенийАдресныхСведений.СоздатьНаборЗаписей();
		УровниСокращенийАдресныхСведений.Записать();

		ЗафиксироватьТранзакцию();
	Исключение
		
		ОтменитьТранзакцию();
		
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Не удалось очистить регистр сведений Уровни сокращений адресных сведений.'",
			ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(
			ИнформацияОбОшибке()));
			
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Процедура ОчиститьИнформациюОЗагрузкеВерсий() Экспорт

	Набор = РегистрыСведений.ЗагруженныеВерсииАдресныхСведений.СоздатьНаборЗаписей();
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(Набор);

КонецПроцедуры

// Вычитываем информацию о адресных сокращениях.
//
Функция АдресныеСокращенияИзФайла(КаталогФайлов)

	Набор = РегистрыСведений.УровниСокращенийАдресныхСведений.СоздатьНаборЗаписей();
	Сведения = Набор.ВыгрузитьКолонки("Сокращение, Уровень, Значение");
	Сведения.Индексы.Добавить("Сокращение, Уровень");

	ТекущаяЗапись = Неопределено;
	ФайлЗагрузки  = ФайлЗагрузкиСубъектаРФ(Неопределено, КаталогФайлов, "SOCRBASE", "AddressStatuses");

	ТекущаяЗапись = ФайлЗагрузки.ФайлЧтения;
	Пока ТекущаяЗапись.Прочитать() Цикл

		Если ТекущаяЗапись.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
			Продолжить;
		КонецЕсли;

		ТипЗаписи = ТекущаяЗапись.ЗначениеАтрибута("TYPE");
		Ключ = ТекущаяЗапись.ЗначениеАтрибута("KEY");

		Если СтрСравнить(ТипЗаписи, "SOCRBASE") = 0 И ЗначениеЗаполнено(Ключ) Тогда
			Запись = Сведения.Добавить();
			Запись.Уровень    = ТекущаяЗапись.ЗначениеАтрибута("ID");
			Запись.Сокращение = Ключ;
			Запись.Значение   = ТекущаяЗапись.ЗначениеАтрибута("VALUE");
		КонецЕсли;
	КонецЦикла;

	Результат = Новый Структура("Сведения", Сведения);
	Результат.Вставить("Версия", ФайлЗагрузки.Версия);
	Результат.Вставить("ДатаВерсии", ФайлЗагрузки.ДатаВерсии);

	ЗакрытьФайлЗагрузкиСубъектаРФ(ФайлЗагрузки);

	Возврат Результат;
КонецФункции

// Инициализирует структуру описания файла данных адресных сведений.
//
Функция ФайлЗагрузкиСубъектаРФ(КодСубъектаРФ, КаталогФайлов, КлючВида, ИмяОписывающегоУзла)

	Если КодСубъектаРФ = Неопределено Тогда
		ИмяИсходногоФайла = КлючВида;
	Иначе
		ИмяИсходногоФайла = Формат(КодСубъектаРФ, "ЧЦ=2; ЧН=; ЧВН=") + "_" + КлючВида;
	КонецЕсли;

	Результат = Новый Структура;
	
	// Как архив
	Файл = НайтиФайл(КаталогФайлов, ИмяИсходногоФайла + ".ZIP");
	Если Файл.Существует Тогда
		ВременныйКаталог = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ПолучитьИмяВременногоФайла());

		ЧтениеZipФайла = Новый ЧтениеZipФайла(Файл.ПолноеИмя);
		Элемент = ЧтениеZipФайла.Элементы[0];
		ЧтениеZipФайла.Извлечь(Элемент, ВременныйКаталог);

		Результат.Вставить("Путь", ВременныйКаталог);
		Результат.Вставить("ПолноеИмя", ВременныйКаталог + Элемент.ПолноеИмя);
		Результат.Вставить("УдалитьПутьПриЗакрытии", Истина);
	Иначе
		// Как обычный файл
		Результат.Вставить("Путь", КаталогФайлов);
		Результат.Вставить("УдалитьПутьПриЗакрытии", Ложь);
		Результат.Вставить("ПолноеИмя", КаталогФайлов + ИмяИсходногоФайла + ".FI");
	КонецЕсли;

	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Примечание,,,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Чтение файла региона %1 из %2'"), КодСубъектаРФ, Результат.ПолноеИмя));
	
	Результат.Вставить("Версия", Неопределено);
	Результат.Вставить("ДатаВерсии", Неопределено);
	Результат.Вставить("ФайлЧтения", Новый ЧтениеFastInfoset);

	Если Не ФайлСуществует(Результат.ПолноеИмя) Тогда
		СписокИзвлеченныхФайлов(КаталогФайлов);
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось загрузить файл %1.
					   |Техническая информация: %2'"), ИмяИсходногоФайла, Результат.ПолноеИмя);
	КонецЕсли;

	ФайлЧтения = Результат.ФайлЧтения;
	ФайлЧтения.ОткрытьФайл(Результат.ПолноеИмя);
	
	// Встаем на первый узел с данными.
	КореньНайден = ФайлЧтения.ПерейтиКСодержимому() <> ТипУзлаXML.Ничего;
	Пока КореньНайден Цикл
		Если ФайлЧтения.ТипУзла = ТипУзлаXML.НачалоЭлемента 
		   И ФайлЧтения.ЛокальноеИмя = ИмяОписывающегоУзла Тогда
			Результат.Версия     = ФайлЧтения.ЗначениеАтрибута("Version");
			Результат.ДатаВерсии = ФайлЧтения.ЗначениеАтрибута("UpdateDate");
			Прервать;
		КонецЕсли;
		КореньНайден = ФайлЧтения.Прочитать();
	КонецЦикла;

	Если Не КореньНайден Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В файле ""%1"" отсутствуют данные по %2'"), Результат.ПолноеИмя, ИмяОписывающегоУзла);
	КонецЕсли;

	Результат.Вставить("КодСубъектаРФ", КодСубъектаРФ);
	Результат.Вставить("КлючВида", КлючВида);

	УказательНаФайл = Новый Файл(Результат.ПолноеИмя);
	Результат.Вставить("РазмерФайла", УказательНаФайл.Размер());

	Возврат Результат;
КонецФункции

Функция КаталогВременногоХранилищаФайлов() Экспорт

	КаталогФайлов = ФайловаяСистема.ОбщийКаталогВременныхФайлов("AdrCls");
	Если Не СтрЗаканчиваетсяНа(КаталогФайлов, ПолучитьРазделительПутиСервера()) Тогда
		КаталогФайлов = КаталогФайлов + ПолучитьРазделительПутиСервера();
	КонецЕсли;

	Возврат КаталогФайлов;

КонецФункции

Функция ФайлСуществует(Знач ПутьДляСохранения)

	ПроверкаФайла = Новый Файл(ПутьДляСохранения);
	Если Не ПроверкаФайла.Существует() Тогда
		Возврат Ложь;
	КонецЕсли;

	Если ПроверкаФайла.ЭтоФайл() Тогда
		Возврат Истина;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

Функция ЗаполненыВсеИдентификаторыОбъекта(Адрес)
	
	Для каждого ИмяУровня Из ИменаУровнейАдреса(Адрес, Истина, Истина) Цикл
		
		Если ЗначениеЗаполнено(Адрес[ИмяУровня]) И ПустаяСтрока(Адрес[ИмяУровня + "Id"]) Тогда
			Возврат Ложь;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#КонецОбласти